tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsGlobalWindowInner.cpp (260638B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "nsGlobalWindowInner.h"
      8 
      9 #include <inttypes.h>
     10 #include <stdio.h>
     11 #include <stdlib.h>
     12 #include <string.h>
     13 
     14 #include <cstdint>
     15 #include <new>
     16 #include <utility>
     17 
     18 #include "AudioChannelService.h"
     19 #include "AutoplayPolicy.h"
     20 #include "Crypto.h"
     21 #include "MainThreadUtils.h"
     22 #include "Navigator.h"
     23 #include "PaintWorkletImpl.h"
     24 #include "SessionStorageCache.h"
     25 #include "Units.h"
     26 #include "VRManagerChild.h"
     27 #include "WindowDestroyedEvent.h"
     28 #include "WindowNamedPropertiesHandler.h"
     29 #include "js/ComparisonOperators.h"
     30 #include "js/CompilationAndEvaluation.h"
     31 #include "js/CompileOptions.h"
     32 #include "js/Id.h"
     33 #include "js/PropertyAndElement.h"  // JS_DefineProperty, JS_GetProperty
     34 #include "js/PropertyDescriptor.h"
     35 #include "js/RealmOptions.h"
     36 #include "js/RootingAPI.h"
     37 #include "js/TypeDecls.h"
     38 #include "js/Value.h"
     39 #include "js/Warnings.h"
     40 #include "js/friend/PerformanceHint.h"
     41 #include "js/loader/LoadedScript.h"
     42 #include "js/shadow/String.h"
     43 #include "jsapi.h"
     44 #include "jsfriendapi.h"
     45 #include "mozIDOMWindow.h"
     46 #include "moz_external_vr.h"
     47 #include "mozilla/AlreadyAddRefed.h"
     48 #include "mozilla/AppShutdown.h"
     49 #include "mozilla/ArrayIterator.h"
     50 #include "mozilla/Attributes.h"
     51 #include "mozilla/BaseProfilerMarkersPrerequisites.h"
     52 #include "mozilla/BasicEvents.h"
     53 #include "mozilla/BounceTrackingStorageObserver.h"
     54 #include "mozilla/CallState.h"
     55 #include "mozilla/Components.h"
     56 #include "mozilla/CycleCollectedJSContext.h"
     57 #include "mozilla/DOMEventTargetHelper.h"
     58 #include "mozilla/ErrorResult.h"
     59 #include "mozilla/EventDispatcher.h"
     60 #include "mozilla/EventListenerManager.h"
     61 #include "mozilla/EventQueue.h"
     62 #include "mozilla/ExtensionPolicyService.h"
     63 #include "mozilla/FloatingPoint.h"
     64 #include "mozilla/FlushType.h"
     65 #include "mozilla/Likely.h"
     66 #include "mozilla/Logging.h"
     67 #include "mozilla/LookAndFeel.h"
     68 #include "mozilla/Maybe.h"
     69 #include "mozilla/OwningNonNull.h"
     70 #include "mozilla/PermissionDelegateHandler.h"
     71 #include "mozilla/Preferences.h"
     72 #include "mozilla/PresShell.h"
     73 #include "mozilla/ProcessHangMonitor.h"
     74 #include "mozilla/RefPtr.h"
     75 #include "mozilla/Result.h"
     76 #include "mozilla/ScrollContainerFrame.h"
     77 #include "mozilla/ScrollTypes.h"
     78 #include "mozilla/SizeOfState.h"
     79 #include "mozilla/SpinEventLoopUntil.h"
     80 #include "mozilla/Sprintf.h"
     81 #include "mozilla/StaticPrefs_browser.h"
     82 #include "mozilla/StaticPrefs_docshell.h"
     83 #include "mozilla/StaticPrefs_dom.h"
     84 #include "mozilla/StaticPrefs_extensions.h"
     85 #include "mozilla/StaticPrefs_privacy.h"
     86 #include "mozilla/StorageAccess.h"
     87 #include "mozilla/StoragePrincipalHelper.h"
     88 #include "mozilla/TelemetryHistogramEnums.h"
     89 #include "mozilla/ThrottledEventQueue.h"
     90 #include "mozilla/TimeStamp.h"
     91 #include "mozilla/UniquePtr.h"
     92 #include "mozilla/dom/AudioContext.h"
     93 #include "mozilla/dom/AutoEntryScript.h"
     94 #include "mozilla/dom/BarProps.h"
     95 #include "mozilla/dom/BindingDeclarations.h"
     96 #include "mozilla/dom/BindingUtils.h"
     97 #include "mozilla/dom/BrowserChild.h"
     98 #include "mozilla/dom/BrowsingContext.h"
     99 #include "mozilla/dom/CSPEvalChecker.h"
    100 #include "mozilla/dom/CallbackDebuggerNotification.h"
    101 #include "mozilla/dom/ChromeMessageBroadcaster.h"
    102 #include "mozilla/dom/ClientInfo.h"
    103 #include "mozilla/dom/ClientManager.h"
    104 #include "mozilla/dom/ClientSource.h"
    105 #include "mozilla/dom/ClientState.h"
    106 #include "mozilla/dom/ClientsBinding.h"
    107 #include "mozilla/dom/CloseWatcher.h"
    108 #include "mozilla/dom/CloseWatcherManager.h"
    109 #include "mozilla/dom/Console.h"
    110 #include "mozilla/dom/ContentChild.h"
    111 #include "mozilla/dom/ContentFrameMessageManager.h"
    112 #include "mozilla/dom/ContentMediaController.h"
    113 #include "mozilla/dom/CookieStore.h"
    114 #include "mozilla/dom/Credential.h"
    115 #include "mozilla/dom/CustomElementRegistry.h"
    116 #include "mozilla/dom/DebuggerNotification.h"
    117 #include "mozilla/dom/DebuggerNotificationBinding.h"
    118 #include "mozilla/dom/DebuggerNotificationManager.h"
    119 #include "mozilla/dom/DocGroup.h"
    120 #include "mozilla/dom/Document.h"
    121 #include "mozilla/dom/DocumentInlines.h"
    122 #include "mozilla/dom/DocumentPictureInPicture.h"
    123 #include "mozilla/dom/Element.h"
    124 #include "mozilla/dom/Event.h"
    125 #include "mozilla/dom/EventTarget.h"
    126 #include "mozilla/dom/External.h"
    127 #include "mozilla/dom/Fetch.h"
    128 #include "mozilla/dom/Gamepad.h"
    129 #include "mozilla/dom/GamepadHandle.h"
    130 #include "mozilla/dom/GamepadManager.h"
    131 #include "mozilla/dom/HashChangeEvent.h"
    132 #include "mozilla/dom/HashChangeEventBinding.h"
    133 #include "mozilla/dom/IDBFactory.h"
    134 #include "mozilla/dom/IdleRequest.h"
    135 #include "mozilla/dom/ImageBitmap.h"
    136 #include "mozilla/dom/ImageBitmapSource.h"
    137 #include "mozilla/dom/IntlUtils.h"
    138 #include "mozilla/dom/JSExecutionUtils.h"  // mozilla::dom::Compile, mozilla::dom::EvaluationExceptionToNSResult
    139 #include "mozilla/dom/LSObject.h"
    140 #include "mozilla/dom/LocalStorage.h"
    141 #include "mozilla/dom/LocalStorageCommon.h"
    142 #include "mozilla/dom/Location.h"
    143 #include "mozilla/dom/MediaDevices.h"
    144 #include "mozilla/dom/MediaKeys.h"
    145 #include "mozilla/dom/Navigation.h"
    146 #include "mozilla/dom/NavigatorBinding.h"
    147 #include "mozilla/dom/Nullable.h"
    148 #include "mozilla/dom/PartitionedLocalStorage.h"
    149 #include "mozilla/dom/Performance.h"
    150 #include "mozilla/dom/PerformanceMainThread.h"
    151 #include "mozilla/dom/PolicyContainer.h"
    152 #include "mozilla/dom/PopStateEvent.h"
    153 #include "mozilla/dom/PopStateEventBinding.h"
    154 #include "mozilla/dom/PopupBlocker.h"
    155 #include "mozilla/dom/PrimitiveConversions.h"
    156 #include "mozilla/dom/Promise.h"
    157 #include "mozilla/dom/RootedDictionary.h"
    158 #include "mozilla/dom/ScriptLoader.h"
    159 #include "mozilla/dom/ScriptSettings.h"
    160 #include "mozilla/dom/ServiceWorker.h"
    161 #include "mozilla/dom/ServiceWorkerDescriptor.h"
    162 #include "mozilla/dom/ServiceWorkerRegistration.h"
    163 #include "mozilla/dom/SessionStorageManager.h"
    164 #include "mozilla/dom/SharedWorker.h"
    165 #include "mozilla/dom/Storage.h"
    166 #include "mozilla/dom/StorageEvent.h"
    167 #include "mozilla/dom/StorageEventBinding.h"
    168 #include "mozilla/dom/StorageNotifierService.h"
    169 #include "mozilla/dom/StorageUtils.h"
    170 #include "mozilla/dom/TabMessageTypes.h"
    171 #include "mozilla/dom/Timeout.h"
    172 #include "mozilla/dom/TimeoutHandler.h"
    173 #include "mozilla/dom/TimeoutManager.h"
    174 #include "mozilla/dom/ToJSValue.h"
    175 #include "mozilla/dom/TrustedTypePolicyFactory.h"
    176 #include "mozilla/dom/TrustedTypeUtils.h"
    177 #include "mozilla/dom/TrustedTypesConstants.h"
    178 #include "mozilla/dom/VRDisplay.h"
    179 #include "mozilla/dom/VRDisplayEvent.h"
    180 #include "mozilla/dom/VRDisplayEventBinding.h"
    181 #include "mozilla/dom/VREventObserver.h"
    182 #include "mozilla/dom/VisualViewport.h"
    183 #include "mozilla/dom/WebCompatBinding.h"
    184 #include "mozilla/dom/WebIDLGlobalNameHash.h"
    185 #include "mozilla/dom/WebIdentityHandler.h"
    186 #include "mozilla/dom/WebTaskSchedulerMainThread.h"
    187 #include "mozilla/dom/WindowBinding.h"
    188 #include "mozilla/dom/WindowContext.h"
    189 #include "mozilla/dom/WindowGlobalChild.h"
    190 #include "mozilla/dom/WindowOrWorkerGlobalScopeBinding.h"
    191 #include "mozilla/dom/WindowProxyHolder.h"
    192 #include "mozilla/dom/WorkerCommon.h"
    193 #include "mozilla/dom/Worklet.h"
    194 #include "mozilla/dom/XRPermissionRequest.h"
    195 #include "mozilla/dom/cache/CacheStorage.h"
    196 #include "mozilla/dom/cache/Types.h"
    197 #include "mozilla/extensions/WebExtensionPolicy.h"
    198 #include "mozilla/fallible.h"
    199 #include "mozilla/gfx/BasePoint.h"
    200 #include "mozilla/gfx/BaseRect.h"
    201 #include "mozilla/gfx/BaseSize.h"
    202 #include "mozilla/gfx/Rect.h"
    203 #include "mozilla/gfx/Types.h"
    204 #include "mozilla/glean/DomMetrics.h"
    205 #include "mozilla/glean/bindings/Glean.h"
    206 #include "mozilla/glean/bindings/GleanPings.h"
    207 #include "mozilla/intl/LocaleService.h"
    208 #include "mozilla/ipc/BackgroundUtils.h"
    209 #include "mozilla/ipc/PBackgroundSharedTypes.h"
    210 #include "mozilla/net/CookieJarSettings.h"
    211 #include "nsAtom.h"
    212 #include "nsBaseHashtable.h"
    213 #include "nsCCUncollectableMarker.h"
    214 #include "nsCOMPtr.h"
    215 #include "nsCRT.h"
    216 #include "nsCRTGlue.h"
    217 #include "nsCanvasFrame.h"
    218 #include "nsCharTraits.h"
    219 #include "nsCheapSets.h"
    220 #include "nsContentUtils.h"
    221 #include "nsCoord.h"
    222 #include "nsCycleCollectionNoteChild.h"
    223 #include "nsCycleCollectionTraversalCallback.h"
    224 #include "nsDOMNavigationTiming.h"
    225 #include "nsDebug.h"
    226 #include "nsDeviceContext.h"
    227 #include "nsDocShell.h"
    228 #include "nsFocusManager.h"
    229 #include "nsFrameMessageManager.h"
    230 #include "nsGkAtoms.h"
    231 #include "nsGlobalWindowOuter.h"
    232 #include "nsHashKeys.h"
    233 #include "nsHistory.h"
    234 #include "nsIAddonPolicyService.h"
    235 #include "nsIArray.h"
    236 #include "nsIBaseWindow.h"
    237 #include "nsIBrowserChild.h"
    238 #include "nsICancelableRunnable.h"
    239 #include "nsIChannel.h"
    240 #include "nsIClipboard.h"
    241 #include "nsIContentSecurityPolicy.h"
    242 #include "nsIControllers.h"
    243 #include "nsICookieJarSettings.h"
    244 #include "nsICookieService.h"
    245 #include "nsID.h"
    246 #include "nsIDOMStorageManager.h"
    247 #include "nsIDOMXULControlElement.h"
    248 #include "nsIDeviceSensors.h"
    249 #include "nsIDocShell.h"
    250 #include "nsIDocShellTreeItem.h"
    251 #include "nsIDocShellTreeOwner.h"
    252 #include "nsIDocumentLoader.h"
    253 #include "nsIDragService.h"
    254 #include "nsIFocusManager.h"
    255 #include "nsIFrame.h"
    256 #include "nsIGlobalObject.h"
    257 #include "nsIIOService.h"
    258 #include "nsIIdleRunnable.h"
    259 #include "nsIInterfaceRequestorUtils.h"
    260 #include "nsILoadContext.h"
    261 #include "nsILoadGroup.h"
    262 #include "nsILoadInfo.h"
    263 #include "nsINamed.h"
    264 #include "nsINode.h"
    265 #include "nsIObserver.h"
    266 #include "nsIObserverService.h"
    267 #include "nsIPermission.h"
    268 #include "nsIPermissionManager.h"
    269 #include "nsIPrefBranch.h"
    270 #include "nsIPrincipal.h"
    271 #include "nsIPrompt.h"
    272 #include "nsIRunnable.h"
    273 #include "nsIScreen.h"
    274 #include "nsIScreenManager.h"
    275 #include "nsIScriptContext.h"
    276 #include "nsIScriptGlobalObject.h"
    277 #include "nsIScriptObjectPrincipal.h"
    278 #include "nsISerialEventTarget.h"
    279 #include "nsISimpleEnumerator.h"
    280 #include "nsISizeOfEventTarget.h"
    281 #include "nsISlowScriptDebug.h"
    282 #include "nsISupportsUtils.h"
    283 #include "nsIThread.h"
    284 #include "nsITimedChannel.h"
    285 #include "nsIURI.h"
    286 #include "nsIWeakReference.h"
    287 #include "nsIWebBrowserChrome.h"
    288 #include "nsIWebNavigation.h"
    289 #include "nsIWebProgressListener.h"
    290 #include "nsIWidget.h"
    291 #include "nsIWidgetListener.h"
    292 #include "nsIXULRuntime.h"
    293 #include "nsJSPrincipals.h"
    294 #include "nsJSUtils.h"
    295 #include "nsLayoutStatics.h"
    296 #include "nsLiteralString.h"
    297 #include "nsNetUtil.h"
    298 #include "nsPIDOMWindow.h"
    299 #include "nsPIDOMWindowInlines.h"
    300 #include "nsPIWindowRoot.h"
    301 #include "nsPoint.h"
    302 #include "nsPresContext.h"
    303 #include "nsQueryObject.h"
    304 #include "nsSandboxFlags.h"
    305 #include "nsScreen.h"
    306 #include "nsServiceManagerUtils.h"
    307 #include "nsString.h"
    308 #include "nsStringFlags.h"
    309 #include "nsStringFwd.h"
    310 #include "nsTArray.h"
    311 #include "nsTLiteralString.h"
    312 #include "nsTObserverArray.h"
    313 #include "nsTStringRepr.h"
    314 #include "nsThreadUtils.h"
    315 #include "nsWeakReference.h"
    316 #include "nsWindowMemoryReporter.h"
    317 #include "nsWindowSizes.h"
    318 #include "nsWrapperCache.h"
    319 #include "nsWrapperCacheInlines.h"
    320 #include "nsXULAppAPI.h"
    321 #include "nsrootidl.h"
    322 #include "prclist.h"
    323 #include "prtypes.h"
    324 #include "xpcprivate.h"
    325 #include "xpcpublic.h"
    326 
    327 #ifdef NS_PRINTING
    328 #  include "nsIPrintSettings.h"
    329 #endif
    330 
    331 #ifdef MOZ_WEBSPEECH
    332 #  include "mozilla/dom/SpeechSynthesis.h"
    333 #endif
    334 
    335 #ifdef ANDROID
    336 #  include <android/log.h>
    337 #endif
    338 
    339 #ifdef XP_WIN
    340 #  include <process.h>
    341 
    342 #  include "mozilla/Debug.h"
    343 #  define getpid _getpid
    344 #else
    345 #  include <unistd.h>  // for getpid()
    346 #endif
    347 
    348 using namespace mozilla;
    349 using namespace mozilla::dom;
    350 using namespace mozilla::dom::ipc;
    351 using mozilla::TimeDuration;
    352 using mozilla::TimeStamp;
    353 using mozilla::dom::GamepadHandle;
    354 using mozilla::dom::cache::CacheStorage;
    355 
    356 #define FORWARD_TO_OUTER(method, args, err_rval)                     \
    357  PR_BEGIN_MACRO                                                     \
    358  RefPtr<nsGlobalWindowOuter> outer = GetOuterWindowInternal();      \
    359  if (!HasActiveDocument()) {                                        \
    360    NS_WARNING(outer ? "Inner window does not have active document." \
    361                     : "No outer window available!");                \
    362    return err_rval;                                                 \
    363  }                                                                  \
    364  return outer->method args;                                         \
    365  PR_END_MACRO
    366 
    367 static nsGlobalWindowOuter* GetOuterWindowForForwarding(
    368    nsGlobalWindowInner* aInner, ErrorResult& aError) {
    369  nsGlobalWindowOuter* outer = aInner->GetOuterWindowInternal();
    370  if (MOZ_LIKELY(aInner->HasActiveDocument())) {
    371    return outer;
    372  }
    373  if (!outer) {
    374    NS_WARNING("No outer window available!");
    375    aError.Throw(NS_ERROR_NOT_INITIALIZED);
    376  } else {
    377    aError.Throw(NS_ERROR_XPC_SECURITY_MANAGER_VETO);
    378  }
    379  return nullptr;
    380 }
    381 
    382 #define FORWARD_TO_OUTER_OR_THROW(method, args, rv, err_rval)                \
    383  PR_BEGIN_MACRO                                                             \
    384  RefPtr<nsGlobalWindowOuter> outer = GetOuterWindowForForwarding(this, rv); \
    385  if (MOZ_LIKELY(outer)) {                                                   \
    386    return outer->method args;                                               \
    387  }                                                                          \
    388  return err_rval;                                                           \
    389  PR_END_MACRO
    390 
    391 #define FORWARD_TO_OUTER_VOID(method, args)                          \
    392  PR_BEGIN_MACRO                                                     \
    393  RefPtr<nsGlobalWindowOuter> outer = GetOuterWindowInternal();      \
    394  if (!HasActiveDocument()) {                                        \
    395    NS_WARNING(outer ? "Inner window does not have active document." \
    396                     : "No outer window available!");                \
    397    return;                                                          \
    398  }                                                                  \
    399  outer->method args;                                                \
    400  return;                                                            \
    401  PR_END_MACRO
    402 
    403 #define ENSURE_ACTIVE_DOCUMENT(errorresult, err_rval) \
    404  PR_BEGIN_MACRO                                      \
    405  if (MOZ_UNLIKELY(!HasActiveDocument())) {           \
    406    aError.Throw(NS_ERROR_XPC_SECURITY_MANAGER_VETO); \
    407    return err_rval;                                  \
    408  }                                                   \
    409  PR_END_MACRO
    410 
    411 #define DOM_TOUCH_LISTENER_ADDED "dom-touch-listener-added"
    412 #define MEMORY_PRESSURE_OBSERVER_TOPIC "memory-pressure"
    413 #define PERMISSION_CHANGED_TOPIC "perm-changed"
    414 
    415 static LazyLogModule gDOMLeakPRLogInner("DOMLeakInner");
    416 extern mozilla::LazyLogModule gTimeoutLog;
    417 
    418 #ifdef DEBUG
    419 static LazyLogModule gDocShellAndDOMWindowLeakLogging(
    420    "DocShellAndDOMWindowLeak");
    421 #endif
    422 
    423 static FILE* gDumpFile = nullptr;
    424 
    425 nsGlobalWindowInner::InnerWindowByIdTable*
    426    nsGlobalWindowInner::sInnerWindowsById = nullptr;
    427 
    428 bool nsGlobalWindowInner::sDragServiceDisabled = false;
    429 bool nsGlobalWindowInner::sMouseDown = false;
    430 
    431 /**
    432 * An indirect observer object that means we don't have to implement nsIObserver
    433 * on nsGlobalWindow, where any script could see it.
    434 */
    435 class nsGlobalWindowObserver final : public nsIObserver,
    436                                     public nsIInterfaceRequestor,
    437                                     public StorageNotificationObserver {
    438 public:
    439  explicit nsGlobalWindowObserver(nsGlobalWindowInner* aWindow)
    440      : mWindow(aWindow) {}
    441  NS_DECL_ISUPPORTS
    442  NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic,
    443                     const char16_t* aData) override {
    444    if (!mWindow) return NS_OK;
    445    return mWindow->Observe(aSubject, aTopic, aData);
    446  }
    447  void Forget() { mWindow = nullptr; }
    448  NS_IMETHOD GetInterface(const nsIID& aIID, void** aResult) override {
    449    if (mWindow && aIID.Equals(NS_GET_IID(nsIDOMWindow)) && mWindow) {
    450      return mWindow->QueryInterface(aIID, aResult);
    451    }
    452    return NS_NOINTERFACE;
    453  }
    454 
    455  void ObserveStorageNotification(StorageEvent* aEvent,
    456                                  const char16_t* aStorageType,
    457                                  bool aPrivateBrowsing) override {
    458    if (mWindow) {
    459      mWindow->ObserveStorageNotification(aEvent, aStorageType,
    460                                          aPrivateBrowsing);
    461    }
    462  }
    463 
    464  nsIPrincipal* GetEffectiveCookiePrincipal() const override {
    465    return mWindow ? mWindow->GetEffectiveCookiePrincipal() : nullptr;
    466  }
    467 
    468  nsIPrincipal* GetEffectiveStoragePrincipal() const override {
    469    return mWindow ? mWindow->GetEffectiveStoragePrincipal() : nullptr;
    470  }
    471 
    472  bool IsPrivateBrowsing() const override {
    473    return mWindow ? mWindow->IsPrivateBrowsing() : false;
    474  }
    475 
    476  nsIEventTarget* GetEventTarget() const override {
    477    return mWindow ? mWindow->SerialEventTarget() : nullptr;
    478  }
    479 
    480 private:
    481  ~nsGlobalWindowObserver() = default;
    482 
    483  // This reference is non-owning and safe because it's cleared by
    484  // nsGlobalWindowInner::FreeInnerObjects().
    485  nsGlobalWindowInner* MOZ_NON_OWNING_REF mWindow;
    486 };
    487 
    488 NS_IMPL_ISUPPORTS(nsGlobalWindowObserver, nsIObserver, nsIInterfaceRequestor)
    489 
    490 class IdleRequestExecutor;
    491 
    492 class IdleRequestExecutorTimeoutHandler final : public TimeoutHandler {
    493 public:
    494  explicit IdleRequestExecutorTimeoutHandler(IdleRequestExecutor* aExecutor)
    495      : mExecutor(aExecutor) {}
    496 
    497  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
    498  NS_DECL_CYCLE_COLLECTION_CLASS(IdleRequestExecutorTimeoutHandler)
    499 
    500  bool Call(const char* /* unused */) override;
    501 
    502 private:
    503  ~IdleRequestExecutorTimeoutHandler() override = default;
    504  RefPtr<IdleRequestExecutor> mExecutor;
    505 };
    506 
    507 NS_IMPL_CYCLE_COLLECTION(IdleRequestExecutorTimeoutHandler, mExecutor)
    508 
    509 NS_IMPL_CYCLE_COLLECTING_ADDREF(IdleRequestExecutorTimeoutHandler)
    510 NS_IMPL_CYCLE_COLLECTING_RELEASE(IdleRequestExecutorTimeoutHandler)
    511 
    512 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestExecutorTimeoutHandler)
    513  NS_INTERFACE_MAP_ENTRY(nsISupports)
    514 NS_INTERFACE_MAP_END
    515 
    516 class IdleRequestExecutor final : public nsIRunnable,
    517                                  public nsICancelableRunnable,
    518                                  public nsINamed,
    519                                  public nsIIdleRunnable {
    520 public:
    521  explicit IdleRequestExecutor(nsGlobalWindowInner* aWindow)
    522      : mDispatched(false), mDeadline(TimeStamp::Now()), mWindow(aWindow) {
    523    MOZ_DIAGNOSTIC_ASSERT(mWindow);
    524 
    525    mIdlePeriodLimit = {mDeadline, mWindow->LastIdleRequestHandle()};
    526    mDelayedExecutorDispatcher = new IdleRequestExecutorTimeoutHandler(this);
    527  }
    528 
    529  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
    530  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(IdleRequestExecutor, nsIRunnable)
    531 
    532  NS_DECL_NSIRUNNABLE
    533  NS_DECL_NSINAMED
    534  nsresult Cancel() override;
    535  void SetDeadline(TimeStamp aDeadline) override;
    536 
    537  bool IsCancelled() const { return !mWindow || mWindow->IsDying(); }
    538  // Checks if aRequest shouldn't execute in the current idle period
    539  // since it has been queued from a chained call to
    540  // requestIdleCallback from within a running idle callback.
    541  bool IneligibleForCurrentIdlePeriod(IdleRequest* aRequest) const {
    542    return aRequest->Handle() >= mIdlePeriodLimit.mLastRequestIdInIdlePeriod &&
    543           TimeStamp::Now() <= mIdlePeriodLimit.mEndOfIdlePeriod;
    544  }
    545 
    546  void MaybeUpdateIdlePeriodLimit();
    547 
    548  // Maybe dispatch the IdleRequestExecutor. MabyeDispatch will
    549  // schedule a delayed dispatch if the associated window is in the
    550  // background or if given a time to wait until dispatching.
    551  void MaybeDispatch(TimeStamp aDelayUntil = TimeStamp());
    552  void ScheduleDispatch();
    553 
    554 private:
    555  struct IdlePeriodLimit {
    556    TimeStamp mEndOfIdlePeriod;
    557    uint32_t mLastRequestIdInIdlePeriod;
    558  };
    559 
    560  void DelayedDispatch(uint32_t aDelay);
    561 
    562  ~IdleRequestExecutor() override = default;
    563 
    564  bool mDispatched;
    565  TimeStamp mDeadline;
    566  IdlePeriodLimit mIdlePeriodLimit;
    567  RefPtr<nsGlobalWindowInner> mWindow;
    568  // The timeout handler responsible for dispatching this executor in
    569  // the case of immediate dispatch to the idle queue isn't
    570  // desirable. This is used if we've dispatched all idle callbacks
    571  // that are allowed to run in the current idle period, or if the
    572  // associated window is currently in the background.
    573  RefPtr<TimeoutHandler> mDelayedExecutorDispatcher;
    574  // If not Nothing() then this value is the handle to the currently
    575  // scheduled delayed executor dispatcher. This is needed to be able
    576  // to cancel the timeout handler in case of the executor being
    577  // cancelled.
    578  Maybe<int32_t> mDelayedExecutorHandle;
    579 };
    580 
    581 NS_IMPL_CYCLE_COLLECTION(IdleRequestExecutor, mWindow,
    582                         mDelayedExecutorDispatcher)
    583 
    584 NS_IMPL_CYCLE_COLLECTING_ADDREF(IdleRequestExecutor)
    585 NS_IMPL_CYCLE_COLLECTING_RELEASE(IdleRequestExecutor)
    586 
    587 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestExecutor)
    588  NS_INTERFACE_MAP_ENTRY(nsIRunnable)
    589  NS_INTERFACE_MAP_ENTRY(nsICancelableRunnable)
    590  NS_INTERFACE_MAP_ENTRY(nsINamed)
    591  NS_INTERFACE_MAP_ENTRY(nsIIdleRunnable)
    592  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRunnable)
    593 NS_INTERFACE_MAP_END
    594 
    595 NS_IMETHODIMP
    596 IdleRequestExecutor::GetName(nsACString& aName) {
    597  aName.AssignLiteral("IdleRequestExecutor");
    598  return NS_OK;
    599 }
    600 
    601 // MOZ_CAN_RUN_SCRIPT_BOUNDARY until nsIRunnable::Run is MOZ_CAN_RUN_SCRIPT.
    602 // See bug 1535398.
    603 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP IdleRequestExecutor::Run() {
    604  MOZ_ASSERT(NS_IsMainThread());
    605 
    606  mDispatched = false;
    607  if (mWindow) {
    608    RefPtr<nsGlobalWindowInner> window(mWindow);
    609    window->ExecuteIdleRequest(mDeadline);
    610  }
    611 
    612  return NS_OK;
    613 }
    614 
    615 nsresult IdleRequestExecutor::Cancel() {
    616  MOZ_ASSERT(NS_IsMainThread());
    617 
    618  if (mDelayedExecutorHandle && mWindow) {
    619    mWindow->GetTimeoutManager()->ClearTimeout(
    620        mDelayedExecutorHandle.value(), Timeout::Reason::eIdleCallbackTimeout);
    621  }
    622 
    623  mWindow = nullptr;
    624  return NS_OK;
    625 }
    626 
    627 void IdleRequestExecutor::SetDeadline(TimeStamp aDeadline) {
    628  MOZ_ASSERT(NS_IsMainThread());
    629 
    630  if (!mWindow) {
    631    return;
    632  }
    633 
    634  mDeadline = aDeadline;
    635 }
    636 
    637 void IdleRequestExecutor::MaybeUpdateIdlePeriodLimit() {
    638  if (TimeStamp::Now() > mIdlePeriodLimit.mEndOfIdlePeriod) {
    639    mIdlePeriodLimit = {mDeadline, mWindow->LastIdleRequestHandle()};
    640  }
    641 }
    642 
    643 void IdleRequestExecutor::MaybeDispatch(TimeStamp aDelayUntil) {
    644  // If we've already dispatched the executor we don't want to do it
    645  // again. Also, if we've called IdleRequestExecutor::Cancel mWindow
    646  // will be null, which indicates that we shouldn't dispatch this
    647  // executor either.
    648  if (mDispatched || IsCancelled()) {
    649    return;
    650  }
    651 
    652  mDispatched = true;
    653 
    654  nsPIDOMWindowOuter* outer = mWindow->GetOuterWindow();
    655  if (outer && outer->IsBackground()) {
    656    // Set a timeout handler with a timeout of 0 ms to throttle idle
    657    // callback requests coming from a backround window using
    658    // background timeout throttling.
    659    DelayedDispatch(0);
    660    return;
    661  }
    662 
    663  TimeStamp now = TimeStamp::Now();
    664  if (!aDelayUntil || aDelayUntil < now) {
    665    ScheduleDispatch();
    666    return;
    667  }
    668 
    669  TimeDuration delay = aDelayUntil - now;
    670  DelayedDispatch(static_cast<uint32_t>(delay.ToMilliseconds()));
    671 }
    672 
    673 void IdleRequestExecutor::ScheduleDispatch() {
    674  MOZ_ASSERT(mWindow);
    675  mDelayedExecutorHandle = Nothing();
    676  RefPtr<IdleRequestExecutor> request = this;
    677  NS_DispatchToCurrentThreadQueue(request.forget(), EventQueuePriority::Idle);
    678 }
    679 
    680 void IdleRequestExecutor::DelayedDispatch(uint32_t aDelay) {
    681  MOZ_ASSERT(mWindow);
    682  MOZ_ASSERT(mDelayedExecutorHandle.isNothing());
    683  int32_t handle;
    684  mWindow->GetTimeoutManager()->SetTimeout(
    685      mDelayedExecutorDispatcher, aDelay, false,
    686      Timeout::Reason::eIdleCallbackTimeout, &handle);
    687  mDelayedExecutorHandle = Some(handle);
    688 }
    689 
    690 bool IdleRequestExecutorTimeoutHandler::Call(const char* /* unused */) {
    691  if (!mExecutor->IsCancelled()) {
    692    mExecutor->ScheduleDispatch();
    693  }
    694  return true;
    695 }
    696 
    697 void nsGlobalWindowInner::ScheduleIdleRequestDispatch() {
    698  AssertIsOnMainThread();
    699 
    700  if (!mIdleRequestExecutor) {
    701    mIdleRequestExecutor = new IdleRequestExecutor(this);
    702  }
    703 
    704  mIdleRequestExecutor->MaybeDispatch();
    705 }
    706 
    707 void nsGlobalWindowInner::SuspendIdleRequests() {
    708  if (mIdleRequestExecutor) {
    709    mIdleRequestExecutor->Cancel();
    710    mIdleRequestExecutor = nullptr;
    711  }
    712 }
    713 
    714 void nsGlobalWindowInner::ResumeIdleRequests() {
    715  MOZ_ASSERT(!mIdleRequestExecutor);
    716 
    717  ScheduleIdleRequestDispatch();
    718 }
    719 
    720 void nsGlobalWindowInner::RemoveIdleCallback(
    721    mozilla::dom::IdleRequest* aRequest) {
    722  AssertIsOnMainThread();
    723 
    724  if (aRequest->HasTimeout()) {
    725    mTimeoutManager->ClearTimeout(aRequest->GetTimeoutHandle(),
    726                                  Timeout::Reason::eIdleCallbackTimeout);
    727  }
    728 
    729  aRequest->removeFrom(mIdleRequestCallbacks);
    730 }
    731 
    732 void nsGlobalWindowInner::RunIdleRequest(IdleRequest* aRequest,
    733                                         DOMHighResTimeStamp aDeadline,
    734                                         bool aDidTimeout) {
    735  AssertIsOnMainThread();
    736  // XXXbz Do we still need this RefPtr?  MOZ_CAN_RUN_SCRIPT should
    737  // guarantee that caller is holding a strong ref on the stack.
    738  RefPtr<IdleRequest> request(aRequest);
    739  RemoveIdleCallback(request);
    740  request->IdleRun(this, aDeadline, aDidTimeout);
    741 }
    742 
    743 void nsGlobalWindowInner::ExecuteIdleRequest(TimeStamp aDeadline) {
    744  AssertIsOnMainThread();
    745  RefPtr<IdleRequest> request = mIdleRequestCallbacks.getFirst();
    746 
    747  if (!request) {
    748    // There are no more idle requests, so stop scheduling idle
    749    // request callbacks.
    750    return;
    751  }
    752 
    753  // If the request that we're trying to execute has been queued
    754  // during the current idle period, then dispatch it again at the end
    755  // of the idle period.
    756  if (mIdleRequestExecutor->IneligibleForCurrentIdlePeriod(request)) {
    757    mIdleRequestExecutor->MaybeDispatch(aDeadline);
    758    return;
    759  }
    760 
    761  DOMHighResTimeStamp deadline = 0.0;
    762 
    763  if (Performance* perf = GetPerformance()) {
    764    deadline = perf->GetDOMTiming()->TimeStampToDOMHighRes(aDeadline);
    765  }
    766 
    767  mIdleRequestExecutor->MaybeUpdateIdlePeriodLimit();
    768  RunIdleRequest(request, deadline, false);
    769 
    770  // Running the idle callback could've suspended the window, in which
    771  // case mIdleRequestExecutor will be null.
    772  if (mIdleRequestExecutor) {
    773    mIdleRequestExecutor->MaybeDispatch();
    774  }
    775 }
    776 
    777 class IdleRequestTimeoutHandler final : public TimeoutHandler {
    778 public:
    779  IdleRequestTimeoutHandler(JSContext* aCx, IdleRequest* aIdleRequest,
    780                            nsPIDOMWindowInner* aWindow)
    781      : TimeoutHandler(aCx), mIdleRequest(aIdleRequest), mWindow(aWindow) {}
    782 
    783  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
    784  NS_DECL_CYCLE_COLLECTION_CLASS(IdleRequestTimeoutHandler)
    785 
    786  MOZ_CAN_RUN_SCRIPT bool Call(const char* /* unused */) override {
    787    RefPtr<nsGlobalWindowInner> window(nsGlobalWindowInner::Cast(mWindow));
    788    RefPtr<IdleRequest> request(mIdleRequest);
    789    window->RunIdleRequest(request, 0.0, true);
    790    return true;
    791  }
    792 
    793 private:
    794  ~IdleRequestTimeoutHandler() override = default;
    795 
    796  RefPtr<IdleRequest> mIdleRequest;
    797  nsCOMPtr<nsPIDOMWindowInner> mWindow;
    798 };
    799 
    800 NS_IMPL_CYCLE_COLLECTION(IdleRequestTimeoutHandler, mIdleRequest, mWindow)
    801 
    802 NS_IMPL_CYCLE_COLLECTING_ADDREF(IdleRequestTimeoutHandler)
    803 NS_IMPL_CYCLE_COLLECTING_RELEASE(IdleRequestTimeoutHandler)
    804 
    805 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IdleRequestTimeoutHandler)
    806  NS_INTERFACE_MAP_ENTRY(nsISupports)
    807 NS_INTERFACE_MAP_END
    808 
    809 uint32_t nsGlobalWindowInner::RequestIdleCallback(
    810    JSContext* aCx, IdleRequestCallback& aCallback,
    811    const IdleRequestOptions& aOptions, ErrorResult& aError) {
    812  AssertIsOnMainThread();
    813 
    814  if (IsDying()) {
    815    return 0;
    816  }
    817 
    818  uint32_t handle = mIdleRequestCallbackCounter++;
    819 
    820  RefPtr<IdleRequest> request = new IdleRequest(&aCallback, handle);
    821 
    822  if (aOptions.mTimeout.WasPassed()) {
    823    int32_t timeoutHandle;
    824    RefPtr<TimeoutHandler> handler(
    825        new IdleRequestTimeoutHandler(aCx, request, this));
    826 
    827    nsresult rv = mTimeoutManager->SetTimeout(
    828        handler, aOptions.mTimeout.Value(), false,
    829        Timeout::Reason::eIdleCallbackTimeout, &timeoutHandle);
    830 
    831    if (NS_WARN_IF(NS_FAILED(rv))) {
    832      return 0;
    833    }
    834 
    835    request->SetTimeoutHandle(timeoutHandle);
    836  }
    837 
    838  mIdleRequestCallbacks.insertBack(request);
    839 
    840  if (!IsSuspended()) {
    841    ScheduleIdleRequestDispatch();
    842  }
    843 
    844  return handle;
    845 }
    846 
    847 void nsGlobalWindowInner::CancelIdleCallback(uint32_t aHandle) {
    848  for (IdleRequest* r : mIdleRequestCallbacks) {
    849    if (r->Handle() == aHandle) {
    850      RemoveIdleCallback(r);
    851      break;
    852    }
    853  }
    854 }
    855 
    856 void nsGlobalWindowInner::DisableIdleCallbackRequests() {
    857  if (mIdleRequestExecutor) {
    858    mIdleRequestExecutor->Cancel();
    859    mIdleRequestExecutor = nullptr;
    860  }
    861 
    862  while (!mIdleRequestCallbacks.isEmpty()) {
    863    RefPtr<IdleRequest> request = mIdleRequestCallbacks.getFirst();
    864    RemoveIdleCallback(request);
    865  }
    866 }
    867 
    868 bool nsGlobalWindowInner::IsBackgroundInternal() const {
    869  return !mOuterWindow || mOuterWindow->IsBackground();
    870 }
    871 
    872 class PromiseDocumentFlushedResolver final {
    873 public:
    874  PromiseDocumentFlushedResolver(Promise* aPromise,
    875                                 PromiseDocumentFlushedCallback& aCallback)
    876      : mPromise(aPromise), mCallback(&aCallback) {}
    877 
    878  virtual ~PromiseDocumentFlushedResolver() = default;
    879 
    880  void Call() {
    881    nsMutationGuard guard;
    882    ErrorResult error;
    883    JS::Rooted<JS::Value> returnVal(RootingCx());
    884    mCallback->Call(&returnVal, error);
    885 
    886    if (error.Failed()) {
    887      mPromise->MaybeReject(std::move(error));
    888    } else if (guard.Mutated(0)) {
    889      // Something within the callback mutated the DOM.
    890      mPromise->MaybeRejectWithNoModificationAllowedError(
    891          "DOM mutated from promiseDocumentFlushed callbacks");
    892    } else {
    893      mPromise->MaybeResolve(returnVal);
    894    }
    895  }
    896 
    897  RefPtr<Promise> mPromise;
    898  RefPtr<PromiseDocumentFlushedCallback> mCallback;
    899 };
    900 
    901 //*****************************************************************************
    902 //***    nsGlobalWindowInner: Object Management
    903 //*****************************************************************************
    904 
    905 nsGlobalWindowInner::nsGlobalWindowInner(nsGlobalWindowOuter* aOuterWindow,
    906                                         WindowGlobalChild* aActor)
    907    : nsPIDOMWindowInner(aOuterWindow, aActor),
    908      mHasOrientationChangeListeners(false),
    909      mWasOffline(false),
    910      mHasHadSlowScript(false),
    911      mIsChrome(false),
    912      mCleanMessageManager(false),
    913      mNeedsFocus(true),
    914      mFocusByKeyOccurred(false),
    915      mDidFireDocElemInserted(false),
    916      mHasGamepad(false),
    917      mHasXRSession(false),
    918      mHasVRDisplayActivateEvents(false),
    919      mXRRuntimeDetectionInFlight(false),
    920      mXRPermissionRequestInFlight(false),
    921      mXRPermissionGranted(false),
    922      mWasCurrentInnerWindow(false),
    923      mHasSeenGamepadInput(false),
    924      mHintedWasLoading(false),
    925      mHasOpenedExternalProtocolFrame(false),
    926      mScrollMarksOnHScrollbar(false),
    927      mStorageAllowedReasonCache(0),
    928      mSuspendDepth(0),
    929      mFreezeDepth(0),
    930 #ifdef DEBUG
    931      mSerial(0),
    932 #endif
    933      mFocusMethod(0),
    934      mIdleRequestCallbackCounter(1),
    935      mIdleRequestExecutor(nullptr),
    936      mObservingRefresh(false),
    937      mIteratingDocumentFlushedResolvers(false),
    938      mCanSkipCCGeneration(0) {
    939  mIsInnerWindow = true;
    940 
    941  AssertIsOnMainThread();
    942  SetIsOnMainThread();
    943  nsLayoutStatics::AddRef();
    944 
    945  // Initialize the PRCList (this).
    946  PR_INIT_CLIST(this);
    947 
    948  // add this inner window to the outer window list of inners.
    949  PR_INSERT_AFTER(this, aOuterWindow);
    950 
    951  mTimeoutManager = MakeUnique<dom::TimeoutManager>(
    952      *this, StaticPrefs::dom_timeout_max_idle_defer_ms(),
    953      static_cast<nsISerialEventTarget*>(nsPIDOMWindowInner::From(this)
    954                                             ->GetBrowsingContextGroup()
    955                                             ->GetTimerEventQueue()));
    956 
    957  mObserver = new nsGlobalWindowObserver(this);
    958  if (nsCOMPtr<nsIObserverService> os = services::GetObserverService()) {
    959    // Watch for online/offline status changes so we can fire events. Use
    960    // a strong reference.
    961    os->AddObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC, false);
    962    os->AddObserver(mObserver, MEMORY_PRESSURE_OBSERVER_TOPIC, false);
    963    os->AddObserver(mObserver, PERMISSION_CHANGED_TOPIC, false);
    964    os->AddObserver(mObserver, "screen-information-changed", false);
    965    os->AddObserver(mObserver, "audio-playback", false);
    966  }
    967 
    968  Preferences::AddStrongObserver(mObserver, "intl.accept_languages");
    969 
    970  // Watch for storage notifications so we can fire storage events.
    971  RefPtr<StorageNotifierService> sns = StorageNotifierService::GetOrCreate();
    972  if (sns) {
    973    sns->Register(mObserver);
    974  }
    975 
    976  if (XRE_IsContentProcess()) {
    977    nsCOMPtr<nsIDocShell> docShell = GetDocShell();
    978    if (docShell) {
    979      mBrowserChild = docShell->GetBrowserChild();
    980    }
    981  }
    982 
    983  if (gDumpFile == nullptr) {
    984    nsAutoCString fname;
    985    Preferences::GetCString("browser.dom.window.dump.file", fname);
    986    if (!fname.IsEmpty()) {
    987      // If this fails to open, Dump() knows to just go to stdout on null.
    988      gDumpFile = fopen(fname.get(), "wb+");
    989    } else {
    990      gDumpFile = stdout;
    991    }
    992  }
    993 
    994 #ifdef DEBUG
    995  mSerial = nsContentUtils::InnerOrOuterWindowCreated();
    996 
    997  MOZ_LOG(gDocShellAndDOMWindowLeakLogging, LogLevel::Info,
    998          ("++DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p]\n",
    999           nsContentUtils::GetCurrentInnerOrOuterWindowCount(),
   1000           static_cast<void*>(ToCanonicalSupports(this)), getpid(), mSerial,
   1001           static_cast<void*>(ToCanonicalSupports(aOuterWindow))));
   1002 #endif
   1003 
   1004  MOZ_LOG(gDOMLeakPRLogInner, LogLevel::Debug,
   1005          ("DOMWINDOW %p created outer=%p", this, aOuterWindow));
   1006 
   1007  // Add ourselves to the inner windows list.
   1008  MOZ_ASSERT(sInnerWindowsById, "Inner Windows hash table must be created!");
   1009  MOZ_ASSERT(!sInnerWindowsById->Contains(mWindowID),
   1010             "This window shouldn't be in the hash table yet!");
   1011  // We seem to see crashes in release builds because of null
   1012  // |sInnerWindowsById|.
   1013  if (sInnerWindowsById) {
   1014    sInnerWindowsById->InsertOrUpdate(mWindowID, this);
   1015  }
   1016 }
   1017 
   1018 #ifdef DEBUG
   1019 
   1020 /* static */
   1021 void nsGlobalWindowInner::AssertIsOnMainThread() {
   1022  MOZ_ASSERT(NS_IsMainThread());
   1023 }
   1024 
   1025 #endif  // DEBUG
   1026 
   1027 /* static */
   1028 void nsGlobalWindowInner::Init() {
   1029  AssertIsOnMainThread();
   1030 
   1031  NS_ASSERTION(gDOMLeakPRLogInner,
   1032               "gDOMLeakPRLogInner should have been initialized!");
   1033 
   1034  sInnerWindowsById = new InnerWindowByIdTable();
   1035 }
   1036 
   1037 nsGlobalWindowInner::~nsGlobalWindowInner() {
   1038  AssertIsOnMainThread();
   1039  MOZ_ASSERT(!mHintedWasLoading);
   1040 
   1041  if (IsChromeWindow()) {
   1042    MOZ_ASSERT(mCleanMessageManager,
   1043               "chrome windows may always disconnect the msg manager");
   1044 
   1045    DisconnectAndClearGroupMessageManagers();
   1046 
   1047    if (mChromeFields.mMessageManager) {
   1048      static_cast<nsFrameMessageManager*>(mChromeFields.mMessageManager.get())
   1049          ->Disconnect();
   1050    }
   1051 
   1052    mCleanMessageManager = false;
   1053  }
   1054 
   1055  // In most cases this should already have been called, but call it again
   1056  // here to catch any corner cases.
   1057  FreeInnerObjects();
   1058 
   1059  if (sInnerWindowsById) {
   1060    sInnerWindowsById->Remove(mWindowID);
   1061  }
   1062 
   1063  nsContentUtils::InnerOrOuterWindowDestroyed();
   1064 
   1065 #ifdef DEBUG
   1066  if (MOZ_LOG_TEST(gDocShellAndDOMWindowLeakLogging, LogLevel::Info)) {
   1067    nsAutoCString url;
   1068    if (mLastOpenedURI) {
   1069      url = mLastOpenedURI->GetSpecOrDefault();
   1070 
   1071      // Data URLs can be very long, so truncate to avoid flooding the log.
   1072      const uint32_t maxURLLength = 1000;
   1073      if (url.Length() > maxURLLength) {
   1074        url.Truncate(maxURLLength);
   1075      }
   1076    }
   1077 
   1078    nsGlobalWindowOuter* outer = nsGlobalWindowOuter::Cast(mOuterWindow);
   1079    MOZ_LOG(
   1080        gDocShellAndDOMWindowLeakLogging, LogLevel::Info,
   1081        ("--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = "
   1082         "%s]\n",
   1083         nsContentUtils::GetCurrentInnerOrOuterWindowCount(),
   1084         static_cast<void*>(ToCanonicalSupports(this)), getpid(), mSerial,
   1085         static_cast<void*>(ToCanonicalSupports(outer)), url.get()));
   1086  }
   1087 #endif
   1088  MOZ_LOG(gDOMLeakPRLogInner, LogLevel::Debug,
   1089          ("DOMWINDOW %p destroyed", this));
   1090 
   1091  // An inner window is destroyed, pull it out of the outer window's
   1092  // list if inner windows.
   1093 
   1094  PR_REMOVE_LINK(this);
   1095 
   1096  // If our outer window's inner window is this window, null out the
   1097  // outer window's reference to this window that's being deleted.
   1098  nsGlobalWindowOuter* outer = GetOuterWindowInternal();
   1099  if (outer) {
   1100    outer->MaybeClearInnerWindow(this);
   1101  }
   1102 
   1103  // We don't have to leave the tab group if we are an inner window.
   1104 
   1105  nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
   1106  if (ac) ac->RemoveWindowAsListener(this);
   1107 
   1108  nsLayoutStatics::Release();
   1109 }
   1110 
   1111 // static
   1112 void nsGlobalWindowInner::ShutDown() {
   1113  AssertIsOnMainThread();
   1114 
   1115  if (gDumpFile && gDumpFile != stdout) {
   1116    fclose(gDumpFile);
   1117  }
   1118  gDumpFile = nullptr;
   1119 
   1120  delete sInnerWindowsById;
   1121  sInnerWindowsById = nullptr;
   1122 }
   1123 
   1124 void nsGlobalWindowInner::FreeInnerObjects() {
   1125  if (IsDying()) {
   1126    return;
   1127  }
   1128  StartDying();
   1129 
   1130  ClearHasPointerRawUpdateEventListeners();
   1131 
   1132  if (mDoc && mDoc->GetWindowContext()) {
   1133    // The document is about to lose its window, so this is a good time to send
   1134    // our page use counters.
   1135    //
   1136    // (We also do this in Document::SetScriptGlobalObject(nullptr), which
   1137    // catches most cases of documents losing their window, but not all.)
   1138    mDoc->SendPageUseCounters();
   1139  }
   1140 
   1141  // Make sure that this is called before we null out the document and
   1142  // other members that the window destroyed observers could
   1143  // re-create.
   1144  if (auto* reporter = nsWindowMemoryReporter::Get()) {
   1145    reporter->ObserveDOMWindowDetached(this);
   1146  }
   1147 
   1148  // Kill all of the workers for this window.
   1149  CancelWorkersForWindow(*this);
   1150 
   1151  for (RefPtr<mozilla::dom::SharedWorker> pinnedWorker :
   1152       mSharedWorkers.ForwardRange()) {
   1153    pinnedWorker->Close();
   1154  }
   1155 
   1156  if (mTimeoutManager) {
   1157    mTimeoutManager->ClearAllTimeouts();
   1158  }
   1159 
   1160  DisableIdleCallbackRequests();
   1161 
   1162  mChromeEventHandler = nullptr;
   1163 
   1164  if (mListenerManager) {
   1165    mListenerManager->RemoveAllListeners();
   1166    mListenerManager->Disconnect();
   1167    mListenerManager = nullptr;
   1168  }
   1169 
   1170  mHistory = nullptr;
   1171 
   1172  mNavigation = nullptr;
   1173 
   1174  if (mNavigator) {
   1175    mNavigator->OnNavigation();
   1176    mNavigator->Invalidate();
   1177    mNavigator = nullptr;
   1178  }
   1179 
   1180  mScreen = nullptr;
   1181 
   1182  if (mDoc) {
   1183    // Remember the document's principal, URI, and policyContainer.
   1184    mDocumentPrincipal = mDoc->NodePrincipal();
   1185    mDocumentCookiePrincipal = mDoc->EffectiveCookiePrincipal();
   1186    mDocumentStoragePrincipal = mDoc->EffectiveStoragePrincipal();
   1187    mDocumentPartitionedPrincipal = mDoc->PartitionedPrincipal();
   1188    mDocumentURI = mDoc->GetDocumentURI();
   1189    mDocBaseURI = mDoc->GetDocBaseURI();
   1190    mDocumentPolicyContainer = mDoc->GetPolicyContainer();
   1191 
   1192    while (mDoc->EventHandlingSuppressed()) {
   1193      mDoc->UnsuppressEventHandlingAndFireEvents(false);
   1194    }
   1195  }
   1196 
   1197  // Remove our reference to the document and the document principal.
   1198  mFocusedElement = nullptr;
   1199 
   1200  nsIGlobalObject::UnlinkObjectsInGlobal();
   1201 
   1202  NotifyWindowIDDestroyed("inner-window-destroyed");
   1203 
   1204  for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
   1205    mAudioContexts[i]->OnWindowDestroy();
   1206  }
   1207  mAudioContexts.Clear();
   1208 
   1209  for (MediaKeys* mediaKeys : mMediaKeysInstances) {
   1210    mediaKeys->OnInnerWindowDestroy();
   1211  }
   1212  mMediaKeysInstances.Clear();
   1213 
   1214  DisableGamepadUpdates();
   1215  mHasGamepad = false;
   1216  mGamepads.Clear();
   1217  DisableVRUpdates();
   1218  mHasXRSession = false;
   1219  mHasVRDisplayActivateEvents = false;
   1220  mXRRuntimeDetectionInFlight = false;
   1221  mXRPermissionRequestInFlight = false;
   1222  mXRPermissionGranted = false;
   1223  mVRDisplays.Clear();
   1224 
   1225  // This breaks a cycle between the window and the ClientSource object.
   1226  mClientSource.reset();
   1227 
   1228  if (mWindowGlobalChild) {
   1229    // Remove any remaining listeners.
   1230    int64_t nListeners = mWindowGlobalChild->BeforeUnloadListeners();
   1231    for (int64_t i = 0; i < nListeners; ++i) {
   1232      mWindowGlobalChild->BeforeUnloadRemoved();
   1233    }
   1234    MOZ_ASSERT(mWindowGlobalChild->BeforeUnloadListeners() == 0);
   1235  }
   1236 
   1237  // If we have any promiseDocumentFlushed callbacks, fire them now so
   1238  // that the Promises can resolve.
   1239  CallDocumentFlushedResolvers(/* aUntilExhaustion = */ true);
   1240 
   1241  DisconnectGlobalTeardownObservers();
   1242 
   1243 #ifdef MOZ_WIDGET_ANDROID
   1244  DisableOrientationChangeListener();
   1245 #endif
   1246 
   1247  if (mObserver) {
   1248    if (nsCOMPtr<nsIObserverService> os = services::GetObserverService()) {
   1249      os->RemoveObserver(mObserver, NS_IOSERVICE_OFFLINE_STATUS_TOPIC);
   1250      os->RemoveObserver(mObserver, MEMORY_PRESSURE_OBSERVER_TOPIC);
   1251      os->RemoveObserver(mObserver, PERMISSION_CHANGED_TOPIC);
   1252      os->RemoveObserver(mObserver, "screen-information-changed");
   1253      os->RemoveObserver(mObserver, "audio-playback");
   1254    }
   1255 
   1256    RefPtr<StorageNotifierService> sns = StorageNotifierService::GetOrCreate();
   1257    if (sns) {
   1258      sns->Unregister(mObserver);
   1259    }
   1260 
   1261    Preferences::RemoveObserver(mObserver, "intl.accept_languages");
   1262 
   1263    // Drop its reference to this dying window, in case for some bogus reason
   1264    // the object stays around.
   1265    mObserver->Forget();
   1266  }
   1267 
   1268  mMenubar = nullptr;
   1269  mToolbar = nullptr;
   1270  mLocationbar = nullptr;
   1271  mPersonalbar = nullptr;
   1272  mStatusbar = nullptr;
   1273  mScrollbars = nullptr;
   1274 
   1275  mConsole = nullptr;
   1276  mCookieStore = nullptr;
   1277  mDocumentPiP = nullptr;
   1278 
   1279  mPaintWorklet = nullptr;
   1280 
   1281  mExternal = nullptr;
   1282 
   1283  if (mLocalStorage) {
   1284    mLocalStorage->Disconnect();
   1285    mLocalStorage = nullptr;
   1286  }
   1287  mSessionStorage = nullptr;
   1288  if (mPerformance) {
   1289    // Since window is dying, nothing is going to be painted
   1290    // with meaningful sizes, so these temp data for LCP is
   1291    // no longer needed.
   1292    static_cast<PerformanceMainThread*>(mPerformance.get())
   1293        ->ClearGeneratedTempDataForLCP();
   1294  }
   1295  mPerformance = nullptr;
   1296 
   1297  mContentMediaController = nullptr;
   1298 
   1299  if (mWebTaskScheduler) {
   1300    mWebTaskScheduler->Disconnect();
   1301    mWebTaskScheduler = nullptr;
   1302  }
   1303 
   1304  mTrustedTypePolicyFactory = nullptr;
   1305 
   1306  mSharedWorkers.Clear();
   1307 
   1308 #ifdef MOZ_WEBSPEECH
   1309  mSpeechSynthesis = nullptr;
   1310 #endif
   1311 
   1312  mGlean = nullptr;
   1313  mGleanPings = nullptr;
   1314 
   1315  mParentTarget = nullptr;
   1316 
   1317  if (mCleanMessageManager) {
   1318    MOZ_ASSERT(mIsChrome, "only chrome should have msg manager cleaned");
   1319    if (mChromeFields.mMessageManager) {
   1320      mChromeFields.mMessageManager->Disconnect();
   1321    }
   1322  }
   1323 
   1324  if (mWindowGlobalChild && !mWindowGlobalChild->IsClosed()) {
   1325    mWindowGlobalChild->Destroy();
   1326  }
   1327 
   1328  mIntlUtils = nullptr;
   1329 
   1330  HintIsLoading(false);
   1331 }
   1332 
   1333 //*****************************************************************************
   1334 // nsGlobalWindowInner::nsISupports
   1335 //*****************************************************************************
   1336 
   1337 // QueryInterface implementation for nsGlobalWindowInner
   1338 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsGlobalWindowInner)
   1339  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   1340  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, EventTarget)
   1341  NS_INTERFACE_MAP_ENTRY(nsIDOMWindow)
   1342  NS_INTERFACE_MAP_ENTRY(nsIGlobalObject)
   1343  NS_INTERFACE_MAP_ENTRY(nsIScriptGlobalObject)
   1344  NS_INTERFACE_MAP_ENTRY(nsIScriptObjectPrincipal)
   1345  NS_INTERFACE_MAP_ENTRY(mozilla::dom::EventTarget)
   1346  NS_INTERFACE_MAP_ENTRY(nsPIDOMWindowInner)
   1347  NS_INTERFACE_MAP_ENTRY(mozIDOMWindow)
   1348  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   1349  NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
   1350 NS_INTERFACE_MAP_END
   1351 
   1352 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGlobalWindowInner)
   1353 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGlobalWindowInner)
   1354 
   1355 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGlobalWindowInner)
   1356  if (tmp->IsBlackForCC(false)) {
   1357    if (nsCCUncollectableMarker::InGeneration(tmp->mCanSkipCCGeneration)) {
   1358      return true;
   1359    }
   1360    tmp->mCanSkipCCGeneration = nsCCUncollectableMarker::sGeneration;
   1361    if (EventListenerManager* elm = tmp->GetExistingListenerManager()) {
   1362      elm->MarkForCC();
   1363    }
   1364    if (tmp->mTimeoutManager) {
   1365      tmp->mTimeoutManager->UnmarkGrayTimers();
   1366    }
   1367    return true;
   1368  }
   1369 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
   1370 
   1371 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGlobalWindowInner)
   1372  return tmp->IsBlackForCC(true);
   1373 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
   1374 
   1375 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGlobalWindowInner)
   1376  return tmp->IsBlackForCC(false);
   1377 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
   1378 
   1379 NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalWindowInner)
   1380 
   1381 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindowInner)
   1382  if (MOZ_UNLIKELY(cb.WantDebugInfo())) {
   1383    char name[512];
   1384    nsAutoCString uri;
   1385    if (tmp->mDoc && tmp->mDoc->GetDocumentURI()) {
   1386      uri = tmp->mDoc->GetDocumentURI()->GetSpecOrDefault();
   1387    }
   1388    SprintfLiteral(name, "nsGlobalWindowInner # %" PRIu64 " inner %s",
   1389                   tmp->mWindowID, uri.get());
   1390    cb.DescribeRefCountedNode(tmp->mRefCnt.get(), name);
   1391  } else {
   1392    NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsGlobalWindowInner, tmp->mRefCnt.get())
   1393  }
   1394 
   1395  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigation)
   1396 
   1397  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNavigator)
   1398 
   1399  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPerformance)
   1400 
   1401  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebTaskScheduler)
   1402 
   1403  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebTaskSchedulingState)
   1404 
   1405  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTrustedTypePolicyFactory)
   1406 
   1407 #ifdef MOZ_WEBSPEECH
   1408  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSpeechSynthesis)
   1409 #endif
   1410 
   1411  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGlean)
   1412  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGleanPings)
   1413 
   1414  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOuterWindow)
   1415 
   1416  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTopInnerWindow)
   1417 
   1418  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager)
   1419 
   1420  if (tmp->mTimeoutManager) {
   1421    tmp->mTimeoutManager->ForEachUnorderedTimeout([&cb](Timeout* timeout) {
   1422      cb.NoteNativeChild(timeout, NS_CYCLE_COLLECTION_PARTICIPANT(Timeout));
   1423    });
   1424  }
   1425 
   1426  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation)
   1427  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHistory)
   1428  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCustomElements)
   1429  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSharedWorkers)
   1430  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStorage)
   1431  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessionStorage)
   1432  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndexedDB)
   1433  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal)
   1434  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentCookiePrincipal)
   1435  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentStoragePrincipal)
   1436  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPartitionedPrincipal)
   1437  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPolicyContainer)
   1438  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowserChild)
   1439  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)
   1440  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebIdentityHandler)
   1441 
   1442  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleRequestExecutor)
   1443  for (IdleRequest* request : tmp->mIdleRequestCallbacks) {
   1444    cb.NoteNativeChild(request, NS_CYCLE_COLLECTION_PARTICIPANT(IdleRequest));
   1445  }
   1446 
   1447  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mClientSource)
   1448 
   1449  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGamepads)
   1450 
   1451  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCacheStorage)
   1452  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVRDisplays)
   1453 
   1454  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDebuggerNotificationManager)
   1455 
   1456  // Traverse stuff from nsPIDOMWindow
   1457  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeEventHandler)
   1458  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentTarget)
   1459  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFocusedElement)
   1460  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBrowsingContext)
   1461  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindowGlobalChild)
   1462  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCloseWatcherManager)
   1463 
   1464  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMenubar)
   1465  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mToolbar)
   1466  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocationbar)
   1467  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPersonalbar)
   1468  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStatusbar)
   1469  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScrollbars)
   1470  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCrypto)
   1471  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsole)
   1472  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCookieStore)
   1473  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPiP)
   1474  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPaintWorklet)
   1475  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExternal)
   1476  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIntlUtils)
   1477  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVisualViewport)
   1478  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCurrentPasteDataTransfer)
   1479 
   1480  tmp->TraverseObjectsInGlobal(cb);
   1481 
   1482  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeFields.mMessageManager)
   1483  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeFields.mGroupMessageManagers)
   1484 
   1485  for (size_t i = 0; i < tmp->mDocumentFlushedResolvers.Length(); i++) {
   1486    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentFlushedResolvers[i]->mPromise);
   1487    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentFlushedResolvers[i]->mCallback);
   1488  }
   1489 
   1490 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
   1491 
   1492 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindowInner)
   1493  NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCE
   1494  if (sInnerWindowsById) {
   1495    sInnerWindowsById->Remove(tmp->mWindowID);
   1496  }
   1497 
   1498  JSObject* wrapper = tmp->GetWrapperPreserveColor();
   1499  if (wrapper) {
   1500    // Mark our realm as dead, so the JS engine won't hand out our
   1501    // global after this point.
   1502    JS::SetRealmNonLive(js::GetNonCCWObjectRealm(wrapper));
   1503  }
   1504 
   1505  NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigation)
   1506 
   1507  NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigator)
   1508 
   1509  NS_IMPL_CYCLE_COLLECTION_UNLINK(mPerformance)
   1510 
   1511  if (tmp->mWebTaskScheduler) {
   1512    tmp->mWebTaskScheduler->Disconnect();
   1513    NS_IMPL_CYCLE_COLLECTION_UNLINK(mWebTaskScheduler)
   1514  }
   1515 
   1516  NS_IMPL_CYCLE_COLLECTION_UNLINK(mWebTaskSchedulingState)
   1517 
   1518  NS_IMPL_CYCLE_COLLECTION_UNLINK(mTrustedTypePolicyFactory)
   1519 
   1520 #ifdef MOZ_WEBSPEECH
   1521  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSpeechSynthesis)
   1522 #endif
   1523 
   1524  NS_IMPL_CYCLE_COLLECTION_UNLINK(mGlean)
   1525  NS_IMPL_CYCLE_COLLECTION_UNLINK(mGleanPings)
   1526 
   1527  if (tmp->mOuterWindow) {
   1528    nsGlobalWindowOuter::Cast(tmp->mOuterWindow)->MaybeClearInnerWindow(tmp);
   1529    NS_IMPL_CYCLE_COLLECTION_UNLINK(mOuterWindow)
   1530  }
   1531 
   1532  if (tmp->mListenerManager) {
   1533    tmp->mListenerManager->Disconnect();
   1534    NS_IMPL_CYCLE_COLLECTION_UNLINK(mListenerManager)
   1535  }
   1536 
   1537  // Here the Timeouts list would've been unlinked, but we rely on
   1538  // that Timeout objects have been traced and will remove themselves
   1539  // while unlinking.
   1540 
   1541  tmp->UpdateTopInnerWindow();
   1542  NS_IMPL_CYCLE_COLLECTION_UNLINK(mTopInnerWindow)
   1543 
   1544  NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation)
   1545  NS_IMPL_CYCLE_COLLECTION_UNLINK(mHistory)
   1546  NS_IMPL_CYCLE_COLLECTION_UNLINK(mNavigation)
   1547  NS_IMPL_CYCLE_COLLECTION_UNLINK(mCustomElements)
   1548  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSharedWorkers)
   1549  if (tmp->mLocalStorage) {
   1550    tmp->mLocalStorage->Disconnect();
   1551    NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStorage)
   1552  }
   1553  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSessionStorage)
   1554  NS_IMPL_CYCLE_COLLECTION_UNLINK(mIndexedDB)
   1555  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal)
   1556  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentCookiePrincipal)
   1557  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentStoragePrincipal)
   1558  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPartitionedPrincipal)
   1559  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPolicyContainer)
   1560  NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowserChild)
   1561  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc)
   1562 
   1563  NS_IMPL_CYCLE_COLLECTION_UNLINK(mGamepads)
   1564 
   1565  NS_IMPL_CYCLE_COLLECTION_UNLINK(mCacheStorage)
   1566  NS_IMPL_CYCLE_COLLECTION_UNLINK(mVRDisplays)
   1567 
   1568  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDebuggerNotificationManager)
   1569 
   1570  // Unlink stuff from nsPIDOMWindow
   1571  NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeEventHandler)
   1572  NS_IMPL_CYCLE_COLLECTION_UNLINK(mParentTarget)
   1573  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFocusedElement)
   1574  NS_IMPL_CYCLE_COLLECTION_UNLINK(mBrowsingContext)
   1575 
   1576  MOZ_DIAGNOSTIC_ASSERT(
   1577      !tmp->mWindowGlobalChild || tmp->mWindowGlobalChild->IsClosed(),
   1578      "How are we unlinking a window before its actor has been destroyed?");
   1579  NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindowGlobalChild)
   1580 
   1581  NS_IMPL_CYCLE_COLLECTION_UNLINK(mMenubar)
   1582  NS_IMPL_CYCLE_COLLECTION_UNLINK(mToolbar)
   1583  NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocationbar)
   1584  NS_IMPL_CYCLE_COLLECTION_UNLINK(mPersonalbar)
   1585  NS_IMPL_CYCLE_COLLECTION_UNLINK(mStatusbar)
   1586  NS_IMPL_CYCLE_COLLECTION_UNLINK(mScrollbars)
   1587  NS_IMPL_CYCLE_COLLECTION_UNLINK(mCrypto)
   1588  NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsole)
   1589  NS_IMPL_CYCLE_COLLECTION_UNLINK(mCookieStore)
   1590  NS_IMPL_CYCLE_COLLECTION_UNLINK(mPaintWorklet)
   1591  NS_IMPL_CYCLE_COLLECTION_UNLINK(mExternal)
   1592  NS_IMPL_CYCLE_COLLECTION_UNLINK(mIntlUtils)
   1593  NS_IMPL_CYCLE_COLLECTION_UNLINK(mVisualViewport)
   1594  NS_IMPL_CYCLE_COLLECTION_UNLINK(mCurrentPasteDataTransfer)
   1595 
   1596  tmp->UnlinkObjectsInGlobal();
   1597 
   1598  NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleRequestExecutor)
   1599 
   1600  // Here the IdleRequest list would've been unlinked, but we rely on
   1601  // that IdleRequest objects have been traced and will remove
   1602  // themselves while unlinking.
   1603 
   1604  NS_IMPL_CYCLE_COLLECTION_UNLINK(mClientSource)
   1605 
   1606  if (tmp->IsChromeWindow()) {
   1607    if (tmp->mChromeFields.mMessageManager) {
   1608      static_cast<nsFrameMessageManager*>(
   1609          tmp->mChromeFields.mMessageManager.get())
   1610          ->Disconnect();
   1611      NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeFields.mMessageManager)
   1612    }
   1613    tmp->DisconnectAndClearGroupMessageManagers();
   1614    NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeFields.mGroupMessageManagers)
   1615  }
   1616 
   1617  for (size_t i = 0; i < tmp->mDocumentFlushedResolvers.Length(); i++) {
   1618    NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentFlushedResolvers[i]->mPromise);
   1619    NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentFlushedResolvers[i]->mCallback);
   1620  }
   1621  tmp->mDocumentFlushedResolvers.Clear();
   1622 
   1623  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
   1624 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
   1625 
   1626 #ifdef DEBUG
   1627 void nsGlobalWindowInner::RiskyUnlink() {
   1628  NS_CYCLE_COLLECTION_INNERNAME.Unlink(this);
   1629 }
   1630 #endif
   1631 
   1632 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindowInner)
   1633  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
   1634 NS_IMPL_CYCLE_COLLECTION_TRACE_END
   1635 
   1636 bool nsGlobalWindowInner::IsBlackForCC(bool aTracingNeeded) {
   1637  if (!nsCCUncollectableMarker::sGeneration) {
   1638    return false;
   1639  }
   1640 
   1641  return (nsCCUncollectableMarker::InGeneration(GetMarkedCCGeneration()) ||
   1642          HasKnownLiveWrapper()) &&
   1643         (!aTracingNeeded || HasNothingToTrace(ToSupports(this)));
   1644 }
   1645 
   1646 //*****************************************************************************
   1647 // nsGlobalWindowInner::nsIScriptGlobalObject
   1648 //*****************************************************************************
   1649 
   1650 bool nsGlobalWindowInner::ShouldResistFingerprinting(RFPTarget aTarget) const {
   1651  if (mDoc) {
   1652    return mDoc->ShouldResistFingerprinting(aTarget);
   1653  }
   1654  return nsContentUtils::ShouldResistFingerprinting(
   1655      "If we do not have a document then we do not have any context"
   1656      "to make an informed RFP choice, so we fall back to the global pref",
   1657      aTarget);
   1658 }
   1659 
   1660 OriginTrials nsGlobalWindowInner::Trials() const {
   1661  return OriginTrials::FromWindow(this);
   1662 }
   1663 
   1664 FontFaceSet* nsGlobalWindowInner::GetFonts() {
   1665  if (mDoc) {
   1666    return mDoc->Fonts();
   1667  }
   1668  return nullptr;
   1669 }
   1670 
   1671 mozilla::Result<mozilla::ipc::PrincipalInfo, nsresult>
   1672 nsGlobalWindowInner::GetStorageKey() {
   1673  MOZ_ASSERT(NS_IsMainThread());
   1674 
   1675  nsIPrincipal* principal = GetEffectiveStoragePrincipal();
   1676  if (!principal) {
   1677    return mozilla::Err(NS_ERROR_FAILURE);
   1678  }
   1679 
   1680  mozilla::ipc::PrincipalInfo principalInfo;
   1681  nsresult rv = PrincipalToPrincipalInfo(principal, &principalInfo);
   1682  if (NS_FAILED(rv)) {
   1683    return mozilla::Err(rv);
   1684  }
   1685 
   1686  // Block expanded and null principals, let content and system through.
   1687  if (principalInfo.type() !=
   1688          mozilla::ipc::PrincipalInfo::TContentPrincipalInfo &&
   1689      principalInfo.type() !=
   1690          mozilla::ipc::PrincipalInfo::TSystemPrincipalInfo) {
   1691    return Err(NS_ERROR_DOM_SECURITY_ERR);
   1692  }
   1693 
   1694  return std::move(principalInfo);
   1695 }
   1696 
   1697 mozilla::dom::StorageManager* nsGlobalWindowInner::GetStorageManager() {
   1698  return Navigator()->Storage();
   1699 }
   1700 
   1701 // https://html.spec.whatwg.org/multipage/web-messaging.html#eligible-for-messaging
   1702 // * a Window object whose associated Document is fully active
   1703 bool nsGlobalWindowInner::IsEligibleForMessaging() { return IsFullyActive(); }
   1704 
   1705 void nsGlobalWindowInner::ReportToConsole(
   1706    uint32_t aErrorFlags, const nsCString& aCategory,
   1707    nsContentUtils::PropertiesFile aFile, const nsCString& aMessageName,
   1708    const nsTArray<nsString>& aParams,
   1709    const mozilla::SourceLocation& aLocation) {
   1710  nsContentUtils::ReportToConsole(aErrorFlags, aCategory, mDoc, aFile,
   1711                                  aMessageName.get(), aParams, aLocation);
   1712 }
   1713 
   1714 nsresult nsGlobalWindowInner::EnsureScriptEnvironment() {
   1715  // NOTE: We can't use FORWARD_TO_OUTER here because we don't want to fail if
   1716  // we're called on an inactive inner window.
   1717  nsGlobalWindowOuter* outer = GetOuterWindowInternal();
   1718  if (!outer) {
   1719    NS_WARNING("No outer window available!");
   1720    return NS_ERROR_FAILURE;
   1721  }
   1722  return outer->EnsureScriptEnvironment();
   1723 }
   1724 
   1725 nsIScriptContext* nsGlobalWindowInner::GetScriptContext() {
   1726  nsGlobalWindowOuter* outer = GetOuterWindowInternal();
   1727  if (!outer) {
   1728    return nullptr;
   1729  }
   1730  return outer->GetScriptContext();
   1731 }
   1732 
   1733 void nsGlobalWindowInner::TraceGlobalJSObject(JSTracer* aTrc) {
   1734  TraceWrapper(aTrc, "active window global");
   1735 }
   1736 
   1737 void nsGlobalWindowInner::UpdateAutoplayPermission() {
   1738  if (!GetWindowContext()) {
   1739    return;
   1740  }
   1741  uint32_t perm =
   1742      media::AutoplayPolicy::GetSiteAutoplayPermission(GetPrincipal());
   1743  if (GetWindowContext()->GetAutoplayPermission() == perm) {
   1744    return;
   1745  }
   1746 
   1747  // Setting autoplay permission on a discarded context has no effect.
   1748  (void)GetWindowContext()->SetAutoplayPermission(perm);
   1749 }
   1750 
   1751 void nsGlobalWindowInner::UpdateShortcutsPermission() {
   1752  if (!GetWindowContext() ||
   1753      !GetWindowContext()->GetBrowsingContext()->IsTop()) {
   1754    // We only cache the shortcuts permission on top-level WindowContexts
   1755    // since we always check the top-level principal for the permission.
   1756    return;
   1757  }
   1758 
   1759  uint32_t perm = GetShortcutsPermission(GetPrincipal());
   1760 
   1761  if (GetWindowContext()->GetShortcutsPermission() == perm) {
   1762    return;
   1763  }
   1764 
   1765  // If the WindowContext is discarded this has no effect.
   1766  (void)GetWindowContext()->SetShortcutsPermission(perm);
   1767 }
   1768 
   1769 /* static */
   1770 uint32_t nsGlobalWindowInner::GetShortcutsPermission(nsIPrincipal* aPrincipal) {
   1771  uint32_t perm = nsIPermissionManager::DENY_ACTION;
   1772  nsCOMPtr<nsIPermissionManager> permMgr =
   1773      mozilla::components::PermissionManager::Service();
   1774  if (aPrincipal && permMgr) {
   1775    permMgr->TestExactPermissionFromPrincipal(aPrincipal, "shortcuts"_ns,
   1776                                              &perm);
   1777  }
   1778  return perm;
   1779 }
   1780 
   1781 void nsGlobalWindowInner::UpdatePopupPermission() {
   1782  if (!GetWindowContext()) {
   1783    return;
   1784  }
   1785 
   1786  uint32_t perm = PopupBlocker::GetPopupPermission(GetPrincipal());
   1787  if (GetWindowContext()->GetPopupPermission() == perm) {
   1788    return;
   1789  }
   1790 
   1791  // If the WindowContext is discarded this has no effect.
   1792  (void)GetWindowContext()->SetPopupPermission(perm);
   1793 }
   1794 
   1795 void nsGlobalWindowInner::UpdatePermissions() {
   1796  if (!GetWindowContext()) {
   1797    return;
   1798  }
   1799 
   1800  nsCOMPtr<nsIPrincipal> principal = GetPrincipal();
   1801  RefPtr<WindowContext> windowContext = GetWindowContext();
   1802 
   1803  WindowContext::Transaction txn;
   1804  txn.SetAutoplayPermission(
   1805      media::AutoplayPolicy::GetSiteAutoplayPermission(principal));
   1806  txn.SetPopupPermission(PopupBlocker::GetPopupPermission(principal));
   1807 
   1808  if (windowContext->IsTop()) {
   1809    txn.SetShortcutsPermission(GetShortcutsPermission(principal));
   1810  }
   1811 
   1812  // Setting permissions on a discarded WindowContext has no effect
   1813  (void)txn.Commit(windowContext);
   1814 }
   1815 
   1816 void nsGlobalWindowInner::InitDocumentDependentState(JSContext* aCx) {
   1817  MOZ_ASSERT(mDoc);
   1818 
   1819  if (MOZ_LOG_TEST(gDOMLeakPRLogInner, LogLevel::Debug)) {
   1820    nsIURI* uri = mDoc->GetDocumentURI();
   1821    MOZ_LOG(gDOMLeakPRLogInner, LogLevel::Debug,
   1822            ("DOMWINDOW %p SetNewDocument %s", this,
   1823             uri ? uri->GetSpecOrDefault().get() : ""));
   1824  }
   1825 
   1826  mFocusedElement = nullptr;
   1827  mLocalStorage = nullptr;
   1828  mSessionStorage = nullptr;
   1829  mPerformance = nullptr;
   1830  if (mWebTaskScheduler) {
   1831    mWebTaskScheduler->Disconnect();
   1832    mWebTaskScheduler = nullptr;
   1833    mWebTaskSchedulingState = nullptr;
   1834  }
   1835 
   1836  // This must be called after nullifying the internal objects because here we
   1837  // could recreate them, calling the getter methods, and store them into the JS
   1838  // slots. If we nullify them after, the slot values and the objects will be
   1839  // out of sync.
   1840  ClearDocumentDependentSlots(aCx);
   1841 
   1842  if (!mWindowGlobalChild) {
   1843    mWindowGlobalChild = WindowGlobalChild::Create(this);
   1844  } else {
   1845    // If the window global existed before the window, it must've come from the
   1846    // AboutBlankInitializer
   1847    MOZ_ASSERT(NS_IsAboutBlankAllowQueryAndFragment(GetDocumentURI()),
   1848               "AboutBlankInitializer should only be used with about:blank");
   1849  }
   1850  MOZ_ASSERT(!GetWindowContext()->HasBeenUserGestureActivated(),
   1851             "WindowContext should always not have user gesture activation at "
   1852             "this point.");
   1853 
   1854  UpdatePermissions();
   1855 
   1856  RefPtr<PermissionDelegateHandler> permDelegateHandler =
   1857      mDoc->GetPermissionDelegateHandler();
   1858 
   1859  if (permDelegateHandler) {
   1860    permDelegateHandler->PopulateAllDelegatedPermissions();
   1861  }
   1862 
   1863 #if defined(MOZ_WIDGET_ANDROID)
   1864  // When we insert the new document to the window in the top-level browsing
   1865  // context, we should reset the status of the request which is used for the
   1866  // previous document.
   1867  if (mWindowGlobalChild && GetBrowsingContext() &&
   1868      !GetBrowsingContext()->GetParent()) {
   1869    // Return value of setting synced field should be checked. See bug 1656492.
   1870    (void)GetBrowsingContext()->ResetGVAutoplayRequestStatus();
   1871  }
   1872 #endif
   1873 
   1874 #ifdef DEBUG
   1875  mLastOpenedURI = mDoc->GetDocumentURI();
   1876 #endif
   1877 }
   1878 
   1879 nsresult nsGlobalWindowInner::EnsureClientSource() {
   1880  MOZ_DIAGNOSTIC_ASSERT(mDoc);
   1881 
   1882  bool newClientSource = false;
   1883 
   1884  // Get the load info for the document if we performed a load.  Be careful not
   1885  // to look at local URLs, though. Local URLs are those that have a scheme of:
   1886  //  * about:
   1887  //  * data:
   1888  //  * blob:
   1889  // We also do an additional check here so that we only treat about:blank
   1890  // and about:srcdoc as local URLs.  Other internal firefox about: URLs should
   1891  // not be treated this way.
   1892  nsCOMPtr<nsILoadInfo> loadInfo;
   1893  nsCOMPtr<nsIChannel> channel = mDoc->GetChannel();
   1894  if (channel) {
   1895    nsCOMPtr<nsIURI> uri;
   1896    (void)channel->GetURI(getter_AddRefs(uri));
   1897 
   1898    bool ignoreLoadInfo = false;
   1899 
   1900    if (uri->SchemeIs("about")) {
   1901      ignoreLoadInfo =
   1902          NS_IsAboutBlankAllowQueryAndFragment(uri) || NS_IsAboutSrcdoc(uri);
   1903    } else {
   1904      // Its not an about: URL, so now check for our other URL types.
   1905      ignoreLoadInfo = uri->SchemeIs("data") || uri->SchemeIs("blob");
   1906    }
   1907 
   1908    if (!ignoreLoadInfo) {
   1909      loadInfo = channel->LoadInfo();
   1910    }
   1911  }
   1912 
   1913  // Take the initial client source from the docshell immediately.  Even if we
   1914  // don't end up using it here we should consume it.
   1915  UniquePtr<ClientSource> initialClientSource;
   1916  nsIDocShell* docshell = GetDocShell();
   1917  if (docshell) {
   1918    initialClientSource = docshell->TakeInitialClientSource();
   1919  }
   1920 
   1921  // Try to get the reserved client from the LoadInfo.  A Client is
   1922  // reserved at the start of the channel load if there is not an
   1923  // initial uncommitted about:blank whose window will be reused. It is also
   1924  // created if the channel load encounters a cross-origin redirect.
   1925  if (loadInfo) {
   1926    UniquePtr<ClientSource> reservedClient =
   1927        loadInfo->TakeReservedClientSource();
   1928    if (reservedClient) {
   1929      mClientSource.reset();
   1930      mClientSource = std::move(reservedClient);
   1931      newClientSource = true;
   1932    }
   1933  }
   1934 
   1935  // We don't have a LoadInfo reserved client, but maybe we should
   1936  // be inheriting an initial one from the docshell.  This means
   1937  // that the docshell started the channel load before creating the
   1938  // initial about:blank document.  This is an optimization, though,
   1939  // and it created an initial Client as a placeholder for the document.
   1940  // In this case we want to inherit this placeholder Client here.
   1941  if (!mClientSource) {
   1942    mClientSource = std::move(initialClientSource);
   1943    if (mClientSource) {
   1944      newClientSource = true;
   1945    }
   1946  }
   1947 
   1948  nsCOMPtr<nsIPrincipal> foreignPartitionedPrincipal;
   1949 
   1950  nsresult rv = StoragePrincipalHelper::GetPrincipal(
   1951      this,
   1952      StaticPrefs::privacy_partition_serviceWorkers()
   1953          ? StoragePrincipalHelper::eForeignPartitionedPrincipal
   1954          : StoragePrincipalHelper::eRegularPrincipal,
   1955      getter_AddRefs(foreignPartitionedPrincipal));
   1956  NS_ENSURE_SUCCESS(rv, rv);
   1957 
   1958  // Verify the final ClientSource principal matches the final document
   1959  // principal.  The ClientChannelHelper handles things like network
   1960  // redirects, but there are other ways the document principal can change.
   1961  // For example, if something sets the nsIChannel.owner property, then
   1962  // the final channel principal can be anything.  Unfortunately there is
   1963  // no good way to detect this until after the channel completes loading.
   1964  //
   1965  // For now we handle this just by reseting the ClientSource.  This will
   1966  // result in a new ClientSource with the correct principal being created.
   1967  // To APIs like ServiceWorker and Clients API it will look like there was
   1968  // an initial content page created that was then immediately replaced.
   1969  // This is pretty close to what we are actually doing.
   1970  if (mClientSource) {
   1971    auto principalOrErr = mClientSource->Info().GetPrincipal();
   1972    nsCOMPtr<nsIPrincipal> clientPrincipal =
   1973        principalOrErr.isOk() ? principalOrErr.unwrap() : nullptr;
   1974    if (!clientPrincipal ||
   1975        !clientPrincipal->Equals(foreignPartitionedPrincipal)) {
   1976      mClientSource.reset();
   1977    }
   1978  }
   1979 
   1980  // If we don't have a reserved client or an initial client, then create
   1981  // one now.  This can happen in certain cases where we avoid preallocating
   1982  // the client in the docshell.  This mainly occurs in situations where
   1983  // the principal is not clearly inherited from the parent; e.g. sandboxed
   1984  // iframes, window.open(), etc.
   1985  //
   1986  // We also do this late ClientSource creation if the final document ended
   1987  // up with a different principal.
   1988  //
   1989  // TODO: We may not be marking initial about:blank documents created
   1990  //       this way as controlled by a service worker properly.  The
   1991  //       controller should be coming from the same place as the inheritted
   1992  //       principal.  We do this in docshell, but as mentioned we aren't
   1993  //       smart enough to handle all cases yet.  For example, a
   1994  //       window.open() with new URL should inherit the controller from
   1995  //       the opener, but we probably don't handle that yet.
   1996  if (!mClientSource) {
   1997    mClientSource = ClientManager::CreateSource(
   1998        ClientType::Window, SerialEventTarget(), foreignPartitionedPrincipal);
   1999    MOZ_DIAGNOSTIC_ASSERT(mClientSource);
   2000    newClientSource = true;
   2001 
   2002    // Note, we don't apply the loadinfo controller below if we create
   2003    // the ClientSource here.
   2004  }
   2005 
   2006  // The load may have started controlling the Client as well.  If
   2007  // so, mark it as controlled immediately here.  The actor may
   2008  // or may not have been notified by the parent side about being
   2009  // controlled yet.
   2010  //
   2011  // Note: We should be careful not to control a client that was created late.
   2012  //       These clients were not seen by the ServiceWorkerManager when it
   2013  //       marked the LoadInfo controlled and it won't know about them.  Its
   2014  //       also possible we are creating the client late due to the final
   2015  //       principal changing and these clients should definitely not be
   2016  //       controlled by a service worker with a different principal.
   2017  else if (loadInfo) {
   2018    const Maybe<ServiceWorkerDescriptor> controller = loadInfo->GetController();
   2019    if (controller.isSome()) {
   2020      mClientSource->SetController(controller.ref());
   2021    }
   2022 
   2023    // We also have to handle the case where te initial about:blank is
   2024    // controlled due to inheritting the service worker from its parent,
   2025    // but the actual nsIChannel load is not covered by any service worker.
   2026    // In this case we want the final page to be uncontrolled.  There is
   2027    // an open spec issue about how exactly this should be handled, but for
   2028    // now we just force creation of a new ClientSource to clear the
   2029    // controller.
   2030    //
   2031    //  https://github.com/w3c/ServiceWorker/issues/1232
   2032    //
   2033    else if (mClientSource->GetController().isSome()) {
   2034      mClientSource.reset();
   2035      mClientSource = ClientManager::CreateSource(
   2036          ClientType::Window, SerialEventTarget(), foreignPartitionedPrincipal);
   2037      MOZ_DIAGNOSTIC_ASSERT(mClientSource);
   2038      newClientSource = true;
   2039    }
   2040  }
   2041 
   2042  if (mClientSource) {
   2043    // Generally the policyContainer is stored within the Client and cached on
   2044    // the document. At the time of policyContainer parsing however, the Client
   2045    // has not been created yet, hence we store the policyContainer on the
   2046    // document and propagate/sync the policyContainer with Client here when we
   2047    // create the Client.
   2048    mClientSource->SetPolicyContainer(mDoc->GetPolicyContainer());
   2049 
   2050    DocGroup* docGroup = GetDocGroup();
   2051    MOZ_DIAGNOSTIC_ASSERT(docGroup);
   2052    mClientSource->SetAgentClusterId(docGroup->AgentClusterId());
   2053 
   2054    if (mWindowGlobalChild) {
   2055      mWindowGlobalChild->SendSetClientInfo(mClientSource->Info().ToIPC());
   2056    }
   2057  }
   2058 
   2059  // Its possible that we got a client just after being frozen in
   2060  // the bfcache.  In that case freeze the client immediately.
   2061  if (newClientSource && IsFrozen()) {
   2062    mClientSource->Freeze();
   2063  }
   2064 
   2065  return NS_OK;
   2066 }
   2067 
   2068 nsresult nsGlobalWindowInner::ExecutionReady() {
   2069  nsresult rv = EnsureClientSource();
   2070  NS_ENSURE_SUCCESS(rv, rv);
   2071 
   2072  rv = mClientSource->WindowExecutionReady(this);
   2073  NS_ENSURE_SUCCESS(rv, rv);
   2074 
   2075  return NS_OK;
   2076 }
   2077 
   2078 void nsGlobalWindowInner::UpdateParentTarget() {
   2079  // NOTE: This method is identical to
   2080  // nsGlobalWindowOuter::UpdateParentTarget(). IF YOU UPDATE THIS METHOD,
   2081  // UPDATE THE OTHER ONE TOO!
   2082 
   2083  // Try to get our frame element's tab child global (its in-process message
   2084  // manager).  If that fails, fall back to the chrome event handler's tab
   2085  // child global, and if it doesn't have one, just use the chrome event
   2086  // handler itself.
   2087 
   2088  nsPIDOMWindowOuter* outer = GetOuterWindow();
   2089  if (!outer) {
   2090    return;
   2091  }
   2092  nsCOMPtr<Element> frameElement = outer->GetFrameElementInternal();
   2093  nsCOMPtr<EventTarget> eventTarget =
   2094      nsContentUtils::TryGetBrowserChildGlobal(frameElement);
   2095 
   2096  if (!eventTarget) {
   2097    nsGlobalWindowOuter* topWin = GetInProcessScriptableTopInternal();
   2098    if (topWin) {
   2099      frameElement = topWin->GetFrameElementInternal();
   2100      eventTarget = nsContentUtils::TryGetBrowserChildGlobal(frameElement);
   2101    }
   2102  }
   2103 
   2104  if (!eventTarget) {
   2105    eventTarget = nsContentUtils::TryGetBrowserChildGlobal(mChromeEventHandler);
   2106  }
   2107 
   2108  if (!eventTarget) {
   2109    eventTarget = mChromeEventHandler;
   2110  }
   2111 
   2112  mParentTarget = eventTarget;
   2113 }
   2114 
   2115 EventTarget* nsGlobalWindowInner::GetTargetForDOMEvent() {
   2116  return GetOuterWindowInternal();
   2117 }
   2118 
   2119 void nsGlobalWindowInner::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
   2120  EventMessage msg = aVisitor.mEvent->mMessage;
   2121 
   2122  aVisitor.mCanHandle = true;
   2123  aVisitor.mForceContentDispatch = true;  // FIXME! Bug 329119
   2124  if (msg == eResize && aVisitor.mEvent->IsTrusted()) {
   2125    // Checking whether the event target is an inner window or not, so we can
   2126    // keep the old behavior also in case a child window is handling resize.
   2127    if (aVisitor.mEvent->mOriginalTarget &&
   2128        aVisitor.mEvent->mOriginalTarget->IsInnerWindow()) {
   2129      mIsHandlingResizeEvent = true;
   2130    }
   2131  } else if (msg == eMouseDown && aVisitor.mEvent->IsTrusted()) {
   2132    sMouseDown = true;
   2133  } else if ((msg == eMouseUp || msg == eDragEnd) &&
   2134             aVisitor.mEvent->IsTrusted()) {
   2135    sMouseDown = false;
   2136    if (sDragServiceDisabled) {
   2137      nsCOMPtr<nsIDragService> ds =
   2138          do_GetService("@mozilla.org/widget/dragservice;1");
   2139      if (ds) {
   2140        sDragServiceDisabled = false;
   2141        ds->Unsuppress();
   2142      }
   2143    }
   2144  }
   2145 
   2146  aVisitor.SetParentTarget(GetParentTarget(), true);
   2147 }
   2148 
   2149 // ckeditor 4 uses UA sniffing to wait for an async load event for its editor
   2150 // iframe. This patch makes it work by delaying the sync-about:blank's load
   2151 // event on such frames. See bug 2002481 and:
   2152 // https://github.com/ckeditor/ckeditor4/blob/c7e59ec199298b6b23f4aa7a7668f18572385bac/plugins/wysiwygarea/plugin.js#L43
   2153 MOZ_CAN_RUN_SCRIPT static bool IsCkEditor4EmptyFrame(Element& aEmbedder) {
   2154  if (!StaticPrefs::dom_about_blank_ckeditor_hack_enabled()) {
   2155    return false;
   2156  }
   2157  const nsAttrValue* classes = aEmbedder.GetClasses();
   2158  // We're looking for an <iframe> with a cke_wysiwyg_frame class. That's the
   2159  // most likely check to fail so do it first.
   2160  if (!classes ||
   2161      !classes->Contains(nsGkAtoms::cke_wysiwyg_frame, eCaseMatters)) {
   2162    return false;
   2163  }
   2164  if (!aEmbedder.IsHTMLElement(nsGkAtoms::iframe)) {
   2165    return false;
   2166  }
   2167  // Additionally, we expect it to have an empty src attribute.
   2168  if (const auto* src = aEmbedder.GetParsedAttr(nsGkAtoms::src);
   2169      !src || !src->IsEmptyString()) {
   2170    return false;
   2171  }
   2172  // Deal with the blocklist here before checking for the ckeditor version
   2173  // (which is potentially observable via JS getters).
   2174  if (aEmbedder.NodePrincipal()->IsURIInPrefList(
   2175          "dom.about-blank-ckeditor-hack.disabled-domains")) {
   2176    return false;
   2177  }
   2178  // Finally, we also get the version string off the embedder's global to be
   2179  // extra sure.
   2180  RefPtr global = aEmbedder.GetOwnerGlobal();
   2181  if (!global || !global->GetGlobalJSObject()) {
   2182    return false;
   2183  }
   2184  AutoJSAPI jsapi;
   2185  if (!jsapi.Init(global)) {
   2186    return false;
   2187  }
   2188  CkEditorProperty property;
   2189  JS::Rooted<JS::Value> v(jsapi.cx(),
   2190                          JS::ObjectValue(*global->GetGlobalJSObject()));
   2191  if (!property.Init(jsapi.cx(), v)) {
   2192    JS_ClearPendingException(jsapi.cx());
   2193    return false;
   2194  }
   2195  const auto* version = [&]() -> const CkEditorVersion* {
   2196    if (property.mCKEDITOR.WasPassed()) {
   2197      return &property.mCKEDITOR.Value();
   2198    }
   2199    if (property.mJEDITOR.WasPassed()) {
   2200      return &property.mJEDITOR.Value();
   2201    }
   2202    return nullptr;
   2203  }();
   2204  if (!version || !StringBeginsWith(version->mVersion, u"4."_ns)) {
   2205    return false;
   2206  }
   2207  aEmbedder.OwnerDoc()->WarnOnceAbout(
   2208      DeprecatedOperations::eCKEditor4CompatHack);
   2209  return true;
   2210 }
   2211 
   2212 MOZ_CAN_RUN_SCRIPT static bool NeedsAsyncLoadEventForInitialDocument(
   2213    nsGlobalWindowInner& aInner, Element& aEmbedder) {
   2214  if (auto* doc = aInner.GetExtantDoc(); !doc || !doc->IsInitialDocument()) {
   2215    return false;
   2216  }
   2217  return IsCkEditor4EmptyFrame(aEmbedder);
   2218 }
   2219 
   2220 void nsGlobalWindowInner::FireFrameLoadEvent() {
   2221  // If we're not in a content frame, or are at a BrowsingContext tree boundary,
   2222  // such as the content-chrome boundary, don't fire the "load" event.
   2223  if (GetBrowsingContext()->IsTopContent() ||
   2224      GetBrowsingContext()->IsChrome()) {
   2225    return;
   2226  }
   2227 
   2228  // If embedder is same-process, fire the event on our embedder element.
   2229  //
   2230  // XXX: Bug 1440212 is looking into potentially changing this behaviour to act
   2231  // more like the remote case when in-process.
   2232  if (RefPtr<Element> element = GetBrowsingContext()->GetEmbedderElement()) {
   2233    if (NeedsAsyncLoadEventForInitialDocument(*this, *element)) {
   2234      (new AsyncEventDispatcher(element, eLoad, CanBubble::eNo))
   2235          ->PostDOMEvent();
   2236      return;
   2237    }
   2238 
   2239    nsEventStatus status = nsEventStatus_eIgnore;
   2240    WidgetEvent event(/* aIsTrusted = */ true, eLoad);
   2241    event.mFlags.mBubbles = false;
   2242    event.mFlags.mCancelable = false;
   2243 
   2244    // Most of the time we could get a pres context to pass in here, but not
   2245    // always (i.e. if this window is not shown there won't be a pres context
   2246    // available). Since we're not firing a GUI event we don't need a pres
   2247    // context anyway so we just pass null as the pres context all the time.
   2248    EventDispatcher::Dispatch(element, nullptr, &event, nullptr, &status);
   2249    return;
   2250  }
   2251 
   2252  // We don't have an in-process embedder. Try to get our `BrowserChild` actor
   2253  // to send a message to that embedder. We want to double-check that our outer
   2254  // window is actually the one at the root of this browserChild though, just in
   2255  // case.
   2256  RefPtr<BrowserChild> browserChild =
   2257      BrowserChild::GetFrom(static_cast<nsPIDOMWindowInner*>(this));
   2258  if (browserChild &&
   2259      !GetBrowsingContext()->GetParentWindowContext()->IsInProcess()) {
   2260    // Double-check that our outer window is actually at the root of this
   2261    // `BrowserChild`, in case we're in an odd maybe-unhosted situation like a
   2262    // print preview dialog.
   2263    nsCOMPtr<nsPIDOMWindowOuter> rootOuter =
   2264        do_GetInterface(browserChild->WebNavigation());
   2265    if (!rootOuter || rootOuter != GetOuterWindow()) {
   2266      return;
   2267    }
   2268 
   2269    (void)browserChild->SendMaybeFireEmbedderLoadEvents(
   2270        EmbedderElementEventType::LoadEvent);
   2271  }
   2272 }
   2273 
   2274 nsresult nsGlobalWindowInner::PostHandleEvent(EventChainPostVisitor& aVisitor) {
   2275  // Return early if there is nothing to do.
   2276  switch (aVisitor.mEvent->mMessage) {
   2277    case eResize:
   2278    case eUnload:
   2279    case eLoad:
   2280      break;
   2281    default:
   2282      return NS_OK;
   2283  }
   2284 
   2285  /* mChromeEventHandler and mContext go dangling in the middle of this
   2286   function under some circumstances (events that destroy the window)
   2287   without this addref. */
   2288  RefPtr<EventTarget> kungFuDeathGrip1(mChromeEventHandler);
   2289  (void)kungFuDeathGrip1;  // These aren't referred to through the function
   2290  nsCOMPtr<nsIScriptContext> kungFuDeathGrip2(GetContextInternal());
   2291  (void)kungFuDeathGrip2;  // These aren't referred to through the function
   2292 
   2293  if (aVisitor.mEvent->mMessage == eResize) {
   2294    mIsHandlingResizeEvent = false;
   2295  } else if (aVisitor.mEvent->mMessage == eUnload &&
   2296             aVisitor.mEvent->IsTrusted()) {
   2297    // If any VR display presentation is active at unload, the next page
   2298    // will receive a vrdisplayactive event to indicate that it should
   2299    // immediately begin vr presentation. This should occur when navigating
   2300    // forwards, navigating backwards, and on page reload.
   2301    for (const auto& display : mVRDisplays) {
   2302      if (display->IsPresenting()) {
   2303        display->StartVRNavigation();
   2304        // Save this VR display ID to trigger vrdisplayactivate event
   2305        // after the next load event.
   2306        nsGlobalWindowOuter* outer = GetOuterWindowInternal();
   2307        if (outer) {
   2308          outer->SetAutoActivateVRDisplayID(display->DisplayId());
   2309        }
   2310 
   2311        // XXX The WebVR 1.1 spec does not define which of multiple VR
   2312        // presenting VR displays will be chosen during navigation.
   2313        // As the underlying platform VR API's currently only allow a single
   2314        // VR display, it is safe to choose the first VR display for now.
   2315        break;
   2316      }
   2317    }
   2318    mIsDocumentLoaded = false;
   2319    // Tell the parent process that the document is not loaded.
   2320    if (mWindowGlobalChild) {
   2321      mWindowGlobalChild->SendUpdateDocumentHasLoaded(mIsDocumentLoaded);
   2322    }
   2323  } else if (aVisitor.mEvent->mMessage == eLoad &&
   2324             aVisitor.mEvent->IsTrusted()) {
   2325    // This is page load event since load events don't propagate to |window|.
   2326    // @see Document::GetEventTargetParent.
   2327    mIsDocumentLoaded = true;
   2328    // Tell the parent process that the document is loaded.
   2329    if (mWindowGlobalChild) {
   2330      mWindowGlobalChild->SendUpdateDocumentHasLoaded(mIsDocumentLoaded);
   2331    }
   2332 
   2333    mTimeoutManager->OnDocumentLoaded();
   2334 
   2335    MOZ_ASSERT(aVisitor.mEvent->IsTrusted());
   2336    FireFrameLoadEvent();
   2337 
   2338    if (mVREventObserver) {
   2339      mVREventObserver->NotifyAfterLoad();
   2340    }
   2341 
   2342    uint32_t autoActivateVRDisplayID = 0;
   2343    nsGlobalWindowOuter* outer = GetOuterWindowInternal();
   2344    if (outer) {
   2345      autoActivateVRDisplayID = outer->GetAutoActivateVRDisplayID();
   2346    }
   2347    if (autoActivateVRDisplayID) {
   2348      DispatchVRDisplayActivate(autoActivateVRDisplayID,
   2349                                VRDisplayEventReason::Navigation);
   2350    }
   2351  }
   2352 
   2353  return NS_OK;
   2354 }
   2355 
   2356 nsresult nsGlobalWindowInner::DefineArgumentsProperty(nsIArray* aArguments) {
   2357  nsIScriptContext* ctx = GetOuterWindowInternal()->mContext;
   2358  NS_ENSURE_TRUE(aArguments && ctx, NS_ERROR_NOT_INITIALIZED);
   2359 
   2360  JS::Rooted<JSObject*> obj(RootingCx(), GetWrapperPreserveColor());
   2361  return ctx->SetProperty(obj, "arguments", aArguments);
   2362 }
   2363 
   2364 //*****************************************************************************
   2365 // nsGlobalWindowInner::nsIScriptObjectPrincipal
   2366 //*****************************************************************************
   2367 
   2368 nsIPrincipal* nsGlobalWindowInner::GetPrincipal() {
   2369  if (mDoc) {
   2370    // If we have a document, get the principal from the document
   2371    return mDoc->NodePrincipal();
   2372  }
   2373 
   2374  if (mDocumentPrincipal) {
   2375    return mDocumentPrincipal;
   2376  }
   2377 
   2378  // If we don't have a principal and we don't have a document we
   2379  // ask the parent window for the principal. This can happen when
   2380  // loading a frameset that has a <frame src="javascript:xxx">, in
   2381  // that case the global window is used in JS before we've loaded
   2382  // a document into the window.
   2383 
   2384  nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
   2385      do_QueryInterface(GetInProcessParentInternal());
   2386 
   2387  if (objPrincipal) {
   2388    return objPrincipal->GetPrincipal();
   2389  }
   2390 
   2391  return nullptr;
   2392 }
   2393 
   2394 nsIPrincipal* nsGlobalWindowInner::GetEffectiveCookiePrincipal() {
   2395  if (mDoc) {
   2396    // If we have a document, get the principal from the document
   2397    return mDoc->EffectiveCookiePrincipal();
   2398  }
   2399 
   2400  if (mDocumentCookiePrincipal) {
   2401    return mDocumentCookiePrincipal;
   2402  }
   2403 
   2404  // If we don't have a cookie principal and we don't have a document we ask
   2405  // the parent window for the cookie principal.
   2406 
   2407  nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
   2408      do_QueryInterface(GetInProcessParentInternal());
   2409 
   2410  if (objPrincipal) {
   2411    return objPrincipal->GetEffectiveCookiePrincipal();
   2412  }
   2413 
   2414  return nullptr;
   2415 }
   2416 
   2417 nsIPrincipal* nsGlobalWindowInner::GetEffectiveStoragePrincipal() {
   2418  if (mDoc) {
   2419    // If we have a document, get the principal from the document
   2420    return mDoc->EffectiveStoragePrincipal();
   2421  }
   2422 
   2423  if (mDocumentStoragePrincipal) {
   2424    return mDocumentStoragePrincipal;
   2425  }
   2426 
   2427  // If we don't have a cookie principal and we don't have a document we ask
   2428  // the parent window for the cookie principal.
   2429 
   2430  nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
   2431      do_QueryInterface(GetInProcessParentInternal());
   2432 
   2433  if (objPrincipal) {
   2434    return objPrincipal->GetEffectiveStoragePrincipal();
   2435  }
   2436 
   2437  return nullptr;
   2438 }
   2439 
   2440 nsIPrincipal* nsGlobalWindowInner::PartitionedPrincipal() {
   2441  if (mDoc) {
   2442    // If we have a document, get the principal from the document
   2443    return mDoc->PartitionedPrincipal();
   2444  }
   2445 
   2446  if (mDocumentPartitionedPrincipal) {
   2447    return mDocumentPartitionedPrincipal;
   2448  }
   2449 
   2450  // If we don't have a partitioned principal and we don't have a document we
   2451  // ask the parent window for the partitioned principal.
   2452 
   2453  nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
   2454      do_QueryInterface(GetInProcessParentInternal());
   2455 
   2456  if (objPrincipal) {
   2457    return objPrincipal->PartitionedPrincipal();
   2458  }
   2459 
   2460  return nullptr;
   2461 }
   2462 
   2463 //*****************************************************************************
   2464 // nsGlobalWindowInner::nsIDOMWindow
   2465 //*****************************************************************************
   2466 
   2467 bool nsPIDOMWindowInner::AddAudioContext(AudioContext* aAudioContext) {
   2468  mAudioContexts.AppendElement(aAudioContext);
   2469 
   2470  // Return true if the context should be muted and false if not.
   2471  nsIDocShell* docShell = GetDocShell();
   2472  return docShell && !docShell->GetAllowMedia() && !aAudioContext->IsOffline();
   2473 }
   2474 
   2475 void nsPIDOMWindowInner::RemoveAudioContext(AudioContext* aAudioContext) {
   2476  mAudioContexts.RemoveElement(aAudioContext);
   2477 }
   2478 
   2479 void nsPIDOMWindowInner::MuteAudioContexts() {
   2480  for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
   2481    if (!mAudioContexts[i]->IsOffline()) {
   2482      mAudioContexts[i]->Mute();
   2483    }
   2484  }
   2485 }
   2486 
   2487 void nsPIDOMWindowInner::UnmuteAudioContexts() {
   2488  for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
   2489    if (!mAudioContexts[i]->IsOffline()) {
   2490      mAudioContexts[i]->Unmute();
   2491    }
   2492  }
   2493 }
   2494 
   2495 WindowProxyHolder nsGlobalWindowInner::Window() {
   2496  return WindowProxyHolder(GetBrowsingContext());
   2497 }
   2498 
   2499 Navigation* nsPIDOMWindowInner::Navigation() {
   2500  if (!mNavigation && Navigation::IsAPIEnabled()) {
   2501    mNavigation = new mozilla::dom::Navigation(this);
   2502  }
   2503 
   2504  return mNavigation;
   2505 }
   2506 
   2507 Navigator* nsPIDOMWindowInner::Navigator() {
   2508  if (!mNavigator) {
   2509    mNavigator = new mozilla::dom::Navigator(this);
   2510  }
   2511 
   2512  return mNavigator;
   2513 }
   2514 
   2515 MediaDevices* nsPIDOMWindowInner::GetExtantMediaDevices() const {
   2516  return mNavigator ? mNavigator->GetExtantMediaDevices() : nullptr;
   2517 }
   2518 
   2519 VisualViewport* nsGlobalWindowInner::VisualViewport() {
   2520  if (!mVisualViewport) {
   2521    mVisualViewport = new mozilla::dom::VisualViewport(this);
   2522  }
   2523  return mVisualViewport;
   2524 }
   2525 
   2526 nsScreen* nsGlobalWindowInner::Screen() {
   2527  if (!mScreen) {
   2528    mScreen = new nsScreen(this);
   2529  }
   2530  return mScreen;
   2531 }
   2532 
   2533 nsHistory* nsGlobalWindowInner::GetHistory(ErrorResult& aError) {
   2534  if (!mHistory) {
   2535    mHistory = new nsHistory(this);
   2536  }
   2537  return mHistory;
   2538 }
   2539 
   2540 CustomElementRegistry* nsGlobalWindowInner::CustomElements() {
   2541  if (!mCustomElements) {
   2542    mCustomElements = new CustomElementRegistry(this);
   2543  }
   2544 
   2545  return mCustomElements;
   2546 }
   2547 
   2548 CustomElementRegistry* nsGlobalWindowInner::GetExistingCustomElements() {
   2549  return mCustomElements;
   2550 }
   2551 
   2552 Performance* nsPIDOMWindowInner::GetPerformance() {
   2553  CreatePerformanceObjectIfNeeded();
   2554  return mPerformance;
   2555 }
   2556 
   2557 void nsPIDOMWindowInner::QueuePerformanceNavigationTiming() {
   2558  CreatePerformanceObjectIfNeeded();
   2559  if (mPerformance) {
   2560    mPerformance->QueueNavigationTimingEntry();
   2561  }
   2562 }
   2563 
   2564 void nsPIDOMWindowInner::CreatePerformanceObjectIfNeeded() {
   2565  if (mPerformance || !mDoc) {
   2566    return;
   2567  }
   2568  RefPtr<nsDOMNavigationTiming> timing = mDoc->GetNavigationTiming();
   2569  nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(mDoc->GetChannel()));
   2570  if (timing) {
   2571    mPerformance = Performance::CreateForMainThread(this, mDoc->NodePrincipal(),
   2572                                                    timing, timedChannel);
   2573  }
   2574 }
   2575 
   2576 bool nsPIDOMWindowInner::IsSecureContext() const {
   2577  return nsGlobalWindowInner::Cast(this)->IsSecureContext();
   2578 }
   2579 
   2580 void nsPIDOMWindowInner::Suspend(bool aIncludeSubWindows) {
   2581  nsGlobalWindowInner::Cast(this)->Suspend(aIncludeSubWindows);
   2582 }
   2583 
   2584 void nsPIDOMWindowInner::Resume(bool aIncludeSubWindows) {
   2585  nsGlobalWindowInner::Cast(this)->Resume(aIncludeSubWindows);
   2586 }
   2587 
   2588 void nsPIDOMWindowInner::SyncStateFromParentWindow() {
   2589  nsGlobalWindowInner::Cast(this)->SyncStateFromParentWindow();
   2590 }
   2591 
   2592 Maybe<ClientInfo> nsPIDOMWindowInner::GetClientInfo() const {
   2593  return nsGlobalWindowInner::Cast(this)->GetClientInfo();
   2594 }
   2595 
   2596 Maybe<ClientState> nsPIDOMWindowInner::GetClientState() const {
   2597  return nsGlobalWindowInner::Cast(this)->GetClientState();
   2598 }
   2599 
   2600 Maybe<ServiceWorkerDescriptor> nsPIDOMWindowInner::GetController() const {
   2601  return nsGlobalWindowInner::Cast(this)->GetController();
   2602 }
   2603 
   2604 void nsPIDOMWindowInner::SetPolicyContainer(
   2605    nsIPolicyContainer* aPolicyContainer) {
   2606  return nsGlobalWindowInner::Cast(this)->SetPolicyContainer(aPolicyContainer);
   2607 }
   2608 
   2609 void nsPIDOMWindowInner::SetPreloadCsp(nsIContentSecurityPolicy* aPreloadCsp) {
   2610  return nsGlobalWindowInner::Cast(this)->SetPreloadCsp(aPreloadCsp);
   2611 }
   2612 
   2613 nsIPolicyContainer* nsPIDOMWindowInner::GetPolicyContainer() {
   2614  return nsGlobalWindowInner::Cast(this)->GetPolicyContainer();
   2615 }
   2616 
   2617 void nsPIDOMWindowInner::NoteCalledRegisterForServiceWorkerScope(
   2618    const nsACString& aScope) {
   2619  nsGlobalWindowInner::Cast(this)->NoteCalledRegisterForServiceWorkerScope(
   2620      aScope);
   2621 }
   2622 
   2623 void nsPIDOMWindowInner::NoteDOMContentLoaded() {
   2624  nsGlobalWindowInner::Cast(this)->NoteDOMContentLoaded();
   2625 }
   2626 
   2627 bool nsGlobalWindowInner::ShouldReportForServiceWorkerScope(
   2628    const nsAString& aScope) {
   2629  bool result = false;
   2630 
   2631  nsPIDOMWindowOuter* topOuter = GetInProcessScriptableTop();
   2632  NS_ENSURE_TRUE(topOuter, false);
   2633 
   2634  nsGlobalWindowInner* topInner =
   2635      nsGlobalWindowInner::Cast(topOuter->GetCurrentInnerWindow());
   2636  NS_ENSURE_TRUE(topInner, false);
   2637 
   2638  topInner->ShouldReportForServiceWorkerScopeInternal(
   2639      NS_ConvertUTF16toUTF8(aScope), &result);
   2640  return result;
   2641 }
   2642 
   2643 void nsGlobalWindowInner::GetInstallTrigger(
   2644    JSContext* aCx, JS::MutableHandle<JSObject*> aResult) {
   2645  // Return nullptr, to avoid breaking "typeof InstallTrigger !== 'undefined"
   2646  // "UA detection" use case.
   2647  //
   2648  // A pref ("extensions.InstallTrigger.enabled"), associated to this
   2649  // property using the [Pref] extended attribute in Window.webidl, hides the
   2650  // entire InstallTrigger property.
   2651  //
   2652  // See Bug 1754441 for more details about this deprecation.
   2653  aResult.set(nullptr);
   2654 }
   2655 
   2656 nsIDOMWindowUtils* nsGlobalWindowInner::GetWindowUtils(ErrorResult& aRv) {
   2657  FORWARD_TO_OUTER_OR_THROW(WindowUtils, (), aRv, nullptr);
   2658 }
   2659 
   2660 bool nsGlobalWindowInner::SynthesizeMouseEvent(
   2661    const nsAString& aType, float aOffsetX, float aOffsetY,
   2662    const SynthesizeMouseEventData& aMouseEventData,
   2663    const SynthesizeMouseEventOptions& aOptions,
   2664    const Optional<OwningNonNull<VoidFunction>>& aCallback,
   2665    ErrorResult& aError) {
   2666  nsIDocShell* docShell = GetDocShell();
   2667  RefPtr<PresShell> presShell = docShell ? docShell->GetPresShell() : nullptr;
   2668  if (!presShell) {
   2669    aError.Throw(NS_ERROR_FAILURE);
   2670    return false;
   2671  }
   2672 
   2673  nsPoint offset;
   2674  nsCOMPtr<nsIWidget> widget = nsContentUtils::GetWidget(presShell, &offset);
   2675  if (!widget) {
   2676    aError.Throw(NS_ERROR_FAILURE);
   2677    return false;
   2678  }
   2679 
   2680  LayoutDeviceIntPoint refPoint = nsContentUtils::ToWidgetPoint(
   2681      CSSPoint(aOffsetX, aOffsetY), offset, presShell->GetPresContext());
   2682  auto result = nsContentUtils::SynthesizeMouseEvent(
   2683      presShell, widget, aType, refPoint, aMouseEventData, aOptions, aCallback);
   2684  if (result.isErr()) {
   2685    aError.Throw(result.unwrapErr());
   2686    return false;
   2687  }
   2688 
   2689  return result.unwrap();
   2690 }
   2691 
   2692 CallState nsGlobalWindowInner::ShouldReportForServiceWorkerScopeInternal(
   2693    const nsACString& aScope, bool* aResultOut) {
   2694  MOZ_DIAGNOSTIC_ASSERT(aResultOut);
   2695 
   2696  // First check to see if this window is controlled.  If so, then we have
   2697  // found a match and are done.
   2698  const Maybe<ServiceWorkerDescriptor> swd = GetController();
   2699  if (swd.isSome() && swd.ref().Scope() == aScope) {
   2700    *aResultOut = true;
   2701    return CallState::Stop;
   2702  }
   2703 
   2704  // Next, check to see if this window has called
   2705  // navigator.serviceWorker.register() for this scope.  If so, then treat this
   2706  // as a match so console reports appear in the devtools console.
   2707  if (mClientSource &&
   2708      mClientSource->CalledRegisterForServiceWorkerScope(aScope)) {
   2709    *aResultOut = true;
   2710    return CallState::Stop;
   2711  }
   2712 
   2713  // Finally check the current docshell nsILoadGroup to see if there are any
   2714  // outstanding navigation requests.  If so, match the scope against the
   2715  // channel's URL.  We want to show console reports during the FetchEvent
   2716  // intercepting the navigation itself.
   2717  nsCOMPtr<nsIDocumentLoader> loader(do_QueryInterface(GetDocShell()));
   2718  if (loader) {
   2719    nsCOMPtr<nsILoadGroup> loadgroup;
   2720    (void)loader->GetLoadGroup(getter_AddRefs(loadgroup));
   2721    if (loadgroup) {
   2722      nsCOMPtr<nsISimpleEnumerator> iter;
   2723      (void)loadgroup->GetRequests(getter_AddRefs(iter));
   2724      if (iter) {
   2725        nsCOMPtr<nsISupports> tmp;
   2726        bool hasMore = true;
   2727        // Check each network request in the load group.
   2728        while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) {
   2729          iter->GetNext(getter_AddRefs(tmp));
   2730          nsCOMPtr<nsIChannel> loadingChannel(do_QueryInterface(tmp));
   2731          // Ignore subresource requests.  Logging for a subresource
   2732          // FetchEvent should be handled above since the client is
   2733          // already controlled.
   2734          if (!loadingChannel ||
   2735              !nsContentUtils::IsNonSubresourceRequest(loadingChannel)) {
   2736            continue;
   2737          }
   2738          nsCOMPtr<nsIURI> loadingURL;
   2739          (void)loadingChannel->GetURI(getter_AddRefs(loadingURL));
   2740          if (!loadingURL) {
   2741            continue;
   2742          }
   2743          nsAutoCString loadingSpec;
   2744          (void)loadingURL->GetSpec(loadingSpec);
   2745          // Perform a simple substring comparison to match the scope
   2746          // against the channel URL.
   2747          if (StringBeginsWith(loadingSpec, aScope)) {
   2748            *aResultOut = true;
   2749            return CallState::Stop;
   2750          }
   2751        }
   2752      }
   2753    }
   2754  }
   2755 
   2756  // The current window doesn't care about this service worker, but maybe
   2757  // one of our child frames does.
   2758  return CallOnInProcessChildren(
   2759      &nsGlobalWindowInner::ShouldReportForServiceWorkerScopeInternal, aScope,
   2760      aResultOut);
   2761 }
   2762 
   2763 void nsGlobalWindowInner::NoteCalledRegisterForServiceWorkerScope(
   2764    const nsACString& aScope) {
   2765  if (!mClientSource) {
   2766    return;
   2767  }
   2768 
   2769  mClientSource->NoteCalledRegisterForServiceWorkerScope(aScope);
   2770 }
   2771 
   2772 void nsGlobalWindowInner::NoteDOMContentLoaded() {
   2773  if (!mClientSource) {
   2774    return;
   2775  }
   2776 
   2777  mClientSource->NoteDOMContentLoaded();
   2778 }
   2779 
   2780 void nsGlobalWindowInner::UpdateTopInnerWindow() {
   2781  if (IsTopInnerWindow() || !mTopInnerWindow) {
   2782    return;
   2783  }
   2784 
   2785  nsGlobalWindowInner::Cast(mTopInnerWindow)
   2786      ->UpdateWebSocketCount(-(int32_t)mNumOfOpenWebSockets);
   2787 }
   2788 
   2789 bool nsGlobalWindowInner::IsInSyncOperation() {
   2790  return GetExtantDoc() && GetExtantDoc()->IsInSyncOperation();
   2791 }
   2792 
   2793 bool nsGlobalWindowInner::IsSharedMemoryAllowedInternal(
   2794    nsIPrincipal* aPrincipal) const {
   2795  MOZ_ASSERT(NS_IsMainThread());
   2796 
   2797  if (StaticPrefs::
   2798          dom_postMessage_sharedArrayBuffer_bypassCOOP_COEP_insecure_enabled()) {
   2799    return true;
   2800  }
   2801 
   2802  if (ExtensionPolicyService::GetSingleton().IsExtensionProcess()) {
   2803    if (auto* basePrincipal = BasePrincipal::Cast(aPrincipal)) {
   2804      if (auto* policy = basePrincipal->AddonPolicy()) {
   2805        return policy->IsPrivileged();
   2806      }
   2807    }
   2808  }
   2809 
   2810  return CrossOriginIsolated();
   2811 }
   2812 
   2813 bool nsGlobalWindowInner::CrossOriginIsolated() const {
   2814  MOZ_ASSERT(NS_IsMainThread());
   2815 
   2816  RefPtr<BrowsingContext> bc = GetBrowsingContext();
   2817  MOZ_DIAGNOSTIC_ASSERT(bc);
   2818  return bc->CrossOriginIsolated();
   2819 }
   2820 
   2821 bool nsGlobalWindowInner::OriginAgentCluster() const {
   2822  if (DocGroup* docGroup = GetDocGroup()) {
   2823    return docGroup->IsOriginKeyed();
   2824  }
   2825  return false;
   2826 }
   2827 
   2828 WindowContext* TopWindowContext(nsPIDOMWindowInner& aWindow) {
   2829  WindowContext* wc = aWindow.GetWindowContext();
   2830  if (!wc) {
   2831    return nullptr;
   2832  }
   2833 
   2834  return wc->TopWindowContext();
   2835 }
   2836 
   2837 void nsPIDOMWindowInner::AddPeerConnection() {
   2838  MOZ_ASSERT(NS_IsMainThread());
   2839  ++mActivePeerConnections;
   2840  if (mActivePeerConnections == 1 && mWindowGlobalChild) {
   2841    mWindowGlobalChild->SendUpdateActivePeerConnectionStatus(
   2842        /*aIsAdded*/ true);
   2843 
   2844    // We need to present having active peer connections immediately. If we need
   2845    // to wait for the parent process to come back with this information we
   2846    // might start throttling.
   2847    if (WindowContext* top = TopWindowContext(*this)) {
   2848      top->TransientSetHasActivePeerConnections();
   2849    }
   2850  }
   2851 }
   2852 
   2853 void nsPIDOMWindowInner::RemovePeerConnection() {
   2854  MOZ_ASSERT(NS_IsMainThread());
   2855  MOZ_ASSERT(mActivePeerConnections > 0);
   2856  --mActivePeerConnections;
   2857  if (mActivePeerConnections == 0 && mWindowGlobalChild) {
   2858    mWindowGlobalChild->SendUpdateActivePeerConnectionStatus(
   2859        /*aIsAdded*/ false);
   2860  }
   2861 }
   2862 
   2863 bool nsGlobalWindowInner::HasActivePeerConnections() {
   2864  MOZ_ASSERT(NS_IsMainThread());
   2865 
   2866  WindowContext* topWindowContext = TopWindowContext(*this);
   2867  return topWindowContext && topWindowContext->GetHasActivePeerConnections();
   2868 }
   2869 
   2870 void nsPIDOMWindowInner::AddMediaKeysInstance(MediaKeys* aMediaKeys) {
   2871  MOZ_ASSERT(NS_IsMainThread());
   2872  mMediaKeysInstances.AppendElement(aMediaKeys);
   2873  if (mWindowGlobalChild && mMediaKeysInstances.Length() == 1) {
   2874    mWindowGlobalChild->BlockBFCacheFor(BFCacheStatus::CONTAINS_EME_CONTENT);
   2875  }
   2876 }
   2877 
   2878 void nsPIDOMWindowInner::RemoveMediaKeysInstance(MediaKeys* aMediaKeys) {
   2879  MOZ_ASSERT(NS_IsMainThread());
   2880  mMediaKeysInstances.RemoveElement(aMediaKeys);
   2881  if (mWindowGlobalChild && mMediaKeysInstances.IsEmpty()) {
   2882    mWindowGlobalChild->UnblockBFCacheFor(BFCacheStatus::CONTAINS_EME_CONTENT);
   2883  }
   2884 }
   2885 
   2886 bool nsPIDOMWindowInner::HasActiveMediaKeysInstance() {
   2887  MOZ_ASSERT(NS_IsMainThread());
   2888  return !mMediaKeysInstances.IsEmpty();
   2889 }
   2890 
   2891 bool nsGlobalWindowInner::IsPlayingAudio() {
   2892  for (uint32_t i = 0; i < mAudioContexts.Length(); i++) {
   2893    if (mAudioContexts[i]->IsRunning()) {
   2894      return true;
   2895    }
   2896  }
   2897  RefPtr<AudioChannelService> acs = AudioChannelService::Get();
   2898  if (!acs) {
   2899    return false;
   2900  }
   2901  auto outer = GetOuterWindow();
   2902  if (!outer) {
   2903    // We've been unlinked and are about to die.  Not a good time to pretend to
   2904    // be playing audio.
   2905    return false;
   2906  }
   2907  return acs->IsWindowActive(outer);
   2908 }
   2909 
   2910 bool nsPIDOMWindowInner::IsDocumentLoaded() const { return mIsDocumentLoaded; }
   2911 
   2912 mozilla::dom::TimeoutManager* nsGlobalWindowInner::GetTimeoutManager() {
   2913  return mTimeoutManager.get();
   2914 }
   2915 
   2916 bool nsGlobalWindowInner::IsRunningTimeout() {
   2917  return GetTimeoutManager()->IsRunningTimeout();
   2918 }
   2919 
   2920 void nsPIDOMWindowInner::TryToCacheTopInnerWindow() {
   2921  if (mHasTriedToCacheTopInnerWindow) {
   2922    return;
   2923  }
   2924 
   2925  nsGlobalWindowInner* window = nsGlobalWindowInner::Cast(this);
   2926 
   2927  MOZ_ASSERT(!window->IsDying());
   2928 
   2929  mHasTriedToCacheTopInnerWindow = true;
   2930 
   2931  MOZ_ASSERT(window);
   2932 
   2933  if (nsCOMPtr<nsPIDOMWindowOuter> topOutter =
   2934          window->GetInProcessScriptableTop()) {
   2935    mTopInnerWindow = topOutter->GetCurrentInnerWindow();
   2936  }
   2937 }
   2938 
   2939 void nsGlobalWindowInner::UpdateActiveIndexedDBDatabaseCount(int32_t aDelta) {
   2940  MOZ_ASSERT(NS_IsMainThread());
   2941 
   2942  if (aDelta == 0) {
   2943    return;
   2944  }
   2945 
   2946  // We count databases but not transactions because only active databases
   2947  // could block throttling.
   2948  uint32_t& counter = mTopInnerWindow
   2949                          ? mTopInnerWindow->mNumOfIndexedDBDatabases
   2950                          : mNumOfIndexedDBDatabases;
   2951 
   2952  counter += aDelta;
   2953 }
   2954 
   2955 bool nsGlobalWindowInner::HasActiveIndexedDBDatabases() const {
   2956  MOZ_ASSERT(NS_IsMainThread());
   2957 
   2958  return mTopInnerWindow ? mTopInnerWindow->mNumOfIndexedDBDatabases > 0
   2959                         : mNumOfIndexedDBDatabases > 0;
   2960 }
   2961 
   2962 void nsGlobalWindowInner::UpdateWebSocketCount(int32_t aDelta) {
   2963  MOZ_ASSERT(NS_IsMainThread());
   2964 
   2965  if (aDelta == 0) {
   2966    return;
   2967  }
   2968 
   2969  if (mTopInnerWindow && !IsTopInnerWindow()) {
   2970    nsGlobalWindowInner::Cast(mTopInnerWindow)->UpdateWebSocketCount(aDelta);
   2971  }
   2972 
   2973  MOZ_DIAGNOSTIC_ASSERT(
   2974      aDelta > 0 || ((aDelta + mNumOfOpenWebSockets) < mNumOfOpenWebSockets));
   2975 
   2976  mNumOfOpenWebSockets += aDelta;
   2977 }
   2978 
   2979 bool nsGlobalWindowInner::HasOpenWebSockets() const {
   2980  MOZ_ASSERT(NS_IsMainThread());
   2981 
   2982  return mNumOfOpenWebSockets ||
   2983         (mTopInnerWindow && mTopInnerWindow->mNumOfOpenWebSockets);
   2984 }
   2985 
   2986 void nsGlobalWindowInner::AudioPlaybackChanged(bool aIsPlayingAudio) {
   2987  AUTO_PROFILER_MARKER_UNTYPED("AudioPlaybackChanged", DOM, {});
   2988  UpdateWorkersPlaybackState(*this, aIsPlayingAudio);
   2989 }
   2990 
   2991 bool nsPIDOMWindowInner::IsCurrentInnerWindow() const {
   2992  if (mozilla::SessionHistoryInParent() && mBrowsingContext &&
   2993      mBrowsingContext->IsInBFCache()) {
   2994    return false;
   2995  }
   2996 
   2997  if (!mBrowsingContext || mBrowsingContext->IsDiscarded()) {
   2998    // If our BrowsingContext has been discarded, we consider ourselves
   2999    // still-current if we were current at the time it was discarded.
   3000    return mOuterWindow && WasCurrentInnerWindow();
   3001  }
   3002 
   3003  nsPIDOMWindowOuter* outer = mBrowsingContext->GetDOMWindow();
   3004  return outer && outer->GetCurrentInnerWindow() == this;
   3005 }
   3006 
   3007 bool nsGlobalWindowInner::HasScheduledNormalOrHighPriorityWebTasks() const {
   3008  return gNumNormalOrHighPriorityQueuesHaveTaskScheduledMainThread > 0;
   3009 }
   3010 
   3011 bool nsPIDOMWindowInner::IsFullyActive() const {
   3012  WindowContext* wc = GetWindowContext();
   3013  if (!wc || wc->IsDiscarded() || !wc->IsCurrent()) {
   3014    return false;
   3015  }
   3016  return GetBrowsingContext()->AncestorsAreCurrent();
   3017 }
   3018 
   3019 void nsPIDOMWindowInner::SetAudioCapture(bool aCapture) {
   3020  RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
   3021  if (service) {
   3022    service->SetWindowAudioCaptured(GetOuterWindow(), mWindowID, aCapture);
   3023  }
   3024 }
   3025 
   3026 void nsGlobalWindowInner::SetActiveLoadingState(bool aIsLoading) {
   3027  MOZ_LOG(
   3028      gTimeoutLog, mozilla::LogLevel::Debug,
   3029      ("SetActiveLoadingState innerwindow %p: %d", (void*)this, aIsLoading));
   3030  if (GetBrowsingContext()) {
   3031    // Setting loading on a discarded context has no effect.
   3032    (void)GetBrowsingContext()->SetLoading(aIsLoading);
   3033  }
   3034 
   3035  if (!nsGlobalWindowInner::Cast(this)->IsChromeWindow()) {
   3036    mTimeoutManager->SetLoading(aIsLoading);
   3037  }
   3038 
   3039  HintIsLoading(aIsLoading);
   3040 }
   3041 
   3042 void nsGlobalWindowInner::HintIsLoading(bool aIsLoading) {
   3043  // Hint to tell the JS GC to use modified triggers during pageload.
   3044  if (mHintedWasLoading != aIsLoading) {
   3045    using namespace js::gc;
   3046    SetPerformanceHint(danger::GetJSContext(), aIsLoading
   3047                                                   ? PerformanceHint::InPageLoad
   3048                                                   : PerformanceHint::Normal);
   3049    mHintedWasLoading = aIsLoading;
   3050  }
   3051 }
   3052 
   3053 // nsISpeechSynthesisGetter
   3054 
   3055 #ifdef MOZ_WEBSPEECH
   3056 SpeechSynthesis* nsGlobalWindowInner::GetSpeechSynthesis(ErrorResult& aError) {
   3057  if (!mSpeechSynthesis) {
   3058    mSpeechSynthesis = new SpeechSynthesis(this);
   3059  }
   3060 
   3061  return mSpeechSynthesis;
   3062 }
   3063 
   3064 bool nsGlobalWindowInner::HasActiveSpeechSynthesis() {
   3065  if (mSpeechSynthesis) {
   3066    return !mSpeechSynthesis->HasEmptyQueue();
   3067  }
   3068 
   3069  return false;
   3070 }
   3071 
   3072 #endif
   3073 
   3074 mozilla::glean::Glean* nsGlobalWindowInner::Glean() {
   3075  if (!mGlean) {
   3076    mGlean = new mozilla::glean::Glean(this);
   3077  }
   3078 
   3079  return mGlean;
   3080 }
   3081 
   3082 mozilla::glean::GleanPings* nsGlobalWindowInner::GleanPings() {
   3083  if (!mGleanPings) {
   3084    mGleanPings = new mozilla::glean::GleanPings();
   3085  }
   3086 
   3087  return mGleanPings;
   3088 }
   3089 
   3090 Nullable<WindowProxyHolder> nsGlobalWindowInner::GetParent(
   3091    ErrorResult& aError) {
   3092  FORWARD_TO_OUTER_OR_THROW(GetParentOuter, (), aError, nullptr);
   3093 }
   3094 
   3095 /**
   3096 * GetInProcessScriptableParent used to be called when a script read
   3097 * window.parent. Under Fission, that is now handled by
   3098 * BrowsingContext::GetParent, and the result is a WindowProxyHolder rather than
   3099 * an actual global window. This method still exists for legacy callers which
   3100 * relied on the old logic, and require in-process windows. However, it only
   3101 * works correctly when no out-of-process frames exist between this window and
   3102 * the top-level window, so it should not be used in new code.
   3103 *
   3104 * In contrast to GetRealParent, GetInProcessScriptableParent respects <iframe
   3105 * mozbrowser> boundaries, so if |this| is contained by an <iframe
   3106 * mozbrowser>, we will return |this| as its own parent.
   3107 */
   3108 nsPIDOMWindowOuter* nsGlobalWindowInner::GetInProcessScriptableParent() {
   3109  FORWARD_TO_OUTER(GetInProcessScriptableParent, (), nullptr);
   3110 }
   3111 
   3112 /**
   3113 * GetInProcessScriptableTop used to be called when a script read window.top.
   3114 * Under Fission, that is now handled by BrowsingContext::Top, and the result is
   3115 * a WindowProxyHolder rather than an actual global window. This method still
   3116 * exists for legacy callers which relied on the old logic, and require
   3117 * in-process windows. However, it only works correctly when no out-of-process
   3118 * frames exist between this window and the top-level window, so it should not
   3119 * be used in new code.
   3120 *
   3121 * In contrast to GetRealTop, GetInProcessScriptableTop respects <iframe
   3122 * mozbrowser> boundaries.  If we encounter a window owned by an <iframe
   3123 * mozbrowser> while walking up the window hierarchy, we'll stop and return that
   3124 * window.
   3125 */
   3126 nsPIDOMWindowOuter* nsGlobalWindowInner::GetInProcessScriptableTop() {
   3127  FORWARD_TO_OUTER(GetInProcessScriptableTop, (), nullptr);
   3128 }
   3129 
   3130 void nsGlobalWindowInner::GetContent(JSContext* aCx,
   3131                                     JS::MutableHandle<JSObject*> aRetval,
   3132                                     CallerType aCallerType,
   3133                                     ErrorResult& aError) {
   3134  FORWARD_TO_OUTER_OR_THROW(GetContentOuter,
   3135                            (aCx, aRetval, aCallerType, aError), aError, );
   3136 }
   3137 
   3138 BarProp* nsGlobalWindowInner::GetMenubar(ErrorResult& aError) {
   3139  if (!mMenubar) {
   3140    mMenubar = new MenubarProp(this);
   3141  }
   3142 
   3143  return mMenubar;
   3144 }
   3145 
   3146 BarProp* nsGlobalWindowInner::GetToolbar(ErrorResult& aError) {
   3147  if (!mToolbar) {
   3148    mToolbar = new ToolbarProp(this);
   3149  }
   3150 
   3151  return mToolbar;
   3152 }
   3153 
   3154 BarProp* nsGlobalWindowInner::GetLocationbar(ErrorResult& aError) {
   3155  if (!mLocationbar) {
   3156    mLocationbar = new LocationbarProp(this);
   3157  }
   3158  return mLocationbar;
   3159 }
   3160 
   3161 BarProp* nsGlobalWindowInner::GetPersonalbar(ErrorResult& aError) {
   3162  if (!mPersonalbar) {
   3163    mPersonalbar = new PersonalbarProp(this);
   3164  }
   3165  return mPersonalbar;
   3166 }
   3167 
   3168 BarProp* nsGlobalWindowInner::GetStatusbar(ErrorResult& aError) {
   3169  if (!mStatusbar) {
   3170    mStatusbar = new StatusbarProp(this);
   3171  }
   3172  return mStatusbar;
   3173 }
   3174 
   3175 BarProp* nsGlobalWindowInner::GetScrollbars(ErrorResult& aError) {
   3176  if (!mScrollbars) {
   3177    mScrollbars = new ScrollbarsProp(this);
   3178  }
   3179 
   3180  return mScrollbars;
   3181 }
   3182 
   3183 bool nsGlobalWindowInner::GetClosed(ErrorResult& aError) {
   3184  // If we're called from JS (which is the only way we should be getting called
   3185  // here) and we reach this point, that means our JS global is the current
   3186  // target of the WindowProxy, which means that we are the "current inner"
   3187  // of our outer. So if FORWARD_TO_OUTER fails to forward, that means the
   3188  // outer is already torn down, which corresponds to the closed state.
   3189  FORWARD_TO_OUTER(GetClosedOuter, (), true);
   3190 }
   3191 
   3192 Nullable<WindowProxyHolder> nsGlobalWindowInner::IndexedGetter(
   3193    uint32_t aIndex) {
   3194  FORWARD_TO_OUTER(IndexedGetterOuter, (aIndex), nullptr);
   3195 }
   3196 
   3197 namespace {
   3198 
   3199 struct InterfaceShimEntry {
   3200  const char* geckoName;
   3201  const char* domName;
   3202 };
   3203 
   3204 }  // anonymous namespace
   3205 
   3206 // We add shims from Components.interfaces.nsIDOMFoo to window.Foo for each
   3207 // interface that has interface constants that sites might be getting off
   3208 // of Ci.
   3209 const InterfaceShimEntry kInterfaceShimMap[] = {
   3210    {"nsIXMLHttpRequest", "XMLHttpRequest"},
   3211    {"nsIDOMDOMException", "DOMException"},
   3212    {"nsIDOMNode", "Node"},
   3213    {"nsIDOMCSSRule", "CSSRule"},
   3214    {"nsIDOMEvent", "Event"},
   3215    {"nsIDOMNSEvent", "Event"},
   3216    {"nsIDOMKeyEvent", "KeyEvent"},
   3217    {"nsIDOMMouseEvent", "MouseEvent"},
   3218    {"nsIDOMMouseScrollEvent", "MouseScrollEvent"},
   3219    {"nsIDOMMutationEvent", "MutationEvent"},
   3220    {"nsIDOMUIEvent", "UIEvent"},
   3221    {"nsIDOMHTMLMediaElement", "HTMLMediaElement"},
   3222    {"nsIDOMRange", "Range"},
   3223    // Think about whether Ci.nsINodeFilter can just go away for websites!
   3224    {"nsIDOMNodeFilter", "NodeFilter"},
   3225    {"nsIDOMXPathResult", "XPathResult"}};
   3226 
   3227 bool nsGlobalWindowInner::ResolveComponentsShim(
   3228    JSContext* aCx, JS::Handle<JSObject*> aGlobal,
   3229    JS::MutableHandle<mozilla::Maybe<JS::PropertyDescriptor>> aDesc) {
   3230  // Warn once.
   3231  nsCOMPtr<Document> doc = GetExtantDoc();
   3232  if (doc) {
   3233    doc->WarnOnceAbout(DeprecatedOperations::eComponents, /* asError = */ true);
   3234    // Keep track of how often this happens.
   3235    doc->SetUseCounter(eUseCounter_custom_ComponentsShimResolved);
   3236  }
   3237 
   3238  // Create a fake Components object.
   3239  AssertSameCompartment(aCx, aGlobal);
   3240  JS::Rooted<JSObject*> components(aCx, JS_NewPlainObject(aCx));
   3241  if (NS_WARN_IF(!components)) {
   3242    return false;
   3243  }
   3244 
   3245  // Create a fake interfaces object.
   3246  JS::Rooted<JSObject*> interfaces(aCx, JS_NewPlainObject(aCx));
   3247  if (NS_WARN_IF(!interfaces)) {
   3248    return false;
   3249  }
   3250  bool ok =
   3251      JS_DefineProperty(aCx, components, "interfaces", interfaces,
   3252                        JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY);
   3253  if (NS_WARN_IF(!ok)) {
   3254    return false;
   3255  }
   3256 
   3257  // Define a bunch of shims from the Ci.nsIDOMFoo to window.Foo for DOM
   3258  // interfaces with constants.
   3259  for (uint32_t i = 0; i < std::size(kInterfaceShimMap); ++i) {
   3260    // Grab the names from the table.
   3261    const char* geckoName = kInterfaceShimMap[i].geckoName;
   3262    const char* domName = kInterfaceShimMap[i].domName;
   3263 
   3264    // Look up the appopriate interface object on the global.
   3265    JS::Rooted<JS::Value> v(aCx, JS::UndefinedValue());
   3266    ok = JS_GetProperty(aCx, aGlobal, domName, &v);
   3267    if (NS_WARN_IF(!ok)) {
   3268      return false;
   3269    }
   3270    if (!v.isObject()) {
   3271      NS_WARNING("Unable to find interface object on global");
   3272      continue;
   3273    }
   3274 
   3275    // Define the shim on the interfaces object.
   3276    ok = JS_DefineProperty(
   3277        aCx, interfaces, geckoName, v,
   3278        JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY);
   3279    if (NS_WARN_IF(!ok)) {
   3280      return false;
   3281    }
   3282  }
   3283 
   3284  aDesc.set(mozilla::Some(JS::PropertyDescriptor::Data(
   3285      JS::ObjectValue(*components),
   3286      {JS::PropertyAttribute::Configurable, JS::PropertyAttribute::Enumerable,
   3287       JS::PropertyAttribute::Writable})));
   3288  return true;
   3289 }
   3290 
   3291 #ifdef RELEASE_OR_BETA
   3292 #  define USE_CONTROLLERS_SHIM
   3293 #endif
   3294 
   3295 #ifdef USE_CONTROLLERS_SHIM
   3296 static const JSClass ControllersShimClass = {"Controllers", 0};
   3297 static const JSClass XULControllersShimClass = {"XULControllers", 0};
   3298 #endif
   3299 
   3300 bool nsGlobalWindowInner::DoResolve(
   3301    JSContext* aCx, JS::Handle<JSObject*> aObj, JS::Handle<jsid> aId,
   3302    JS::MutableHandle<mozilla::Maybe<JS::PropertyDescriptor>> aDesc) {
   3303  // Note: Keep this in sync with MayResolve.
   3304 
   3305  // Note: The infallibleInit call in GlobalResolve depends on this check.
   3306  if (!aId.isString()) {
   3307    return true;
   3308  }
   3309 
   3310  bool found;
   3311  if (!WebIDLGlobalNameHash::DefineIfEnabled(aCx, aObj, aId, aDesc, &found)) {
   3312    return false;
   3313  }
   3314 
   3315  if (found) {
   3316    return true;
   3317  }
   3318 
   3319  // We support a cut-down Components.interfaces in case websites are
   3320  // using Components.interfaces.nsIFoo.CONSTANT_NAME for the ones
   3321  // that have constants.
   3322  if (StaticPrefs::dom_use_components_shim() &&
   3323      aId == XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_COMPONENTS)) {
   3324    return ResolveComponentsShim(aCx, aObj, aDesc);
   3325  }
   3326 
   3327  // We also support a "window.controllers" thing; apparently some
   3328  // sites use it for browser-sniffing.  See bug 1010577.
   3329 #ifdef USE_CONTROLLERS_SHIM
   3330  // Note: We use |aObj| rather than |this| to get the principal here, because
   3331  // this is called during Window setup when the Document isn't necessarily
   3332  // hooked up yet.
   3333  if ((aId == XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_CONTROLLERS) ||
   3334       aId == XPCJSRuntime::Get()->GetStringID(
   3335                  XPCJSContext::IDX_CONTROLLERS_CLASS)) &&
   3336      !xpc::IsXrayWrapper(aObj) &&
   3337      !nsContentUtils::ObjectPrincipal(aObj)->IsSystemPrincipal()) {
   3338    if (GetExtantDoc()) {
   3339      GetExtantDoc()->WarnOnceAbout(
   3340          DeprecatedOperations::eWindow_Cc_ontrollers);
   3341    }
   3342    const JSClass* clazz;
   3343    if (aId ==
   3344        XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_CONTROLLERS)) {
   3345      clazz = &XULControllersShimClass;
   3346    } else {
   3347      clazz = &ControllersShimClass;
   3348    }
   3349    MOZ_ASSERT(JS_IsGlobalObject(aObj));
   3350    JS::Rooted<JSObject*> shim(aCx, JS_NewObject(aCx, clazz));
   3351    if (NS_WARN_IF(!shim)) {
   3352      return false;
   3353    }
   3354 
   3355    aDesc.set(mozilla::Some(JS::PropertyDescriptor::Data(
   3356        JS::ObjectValue(*shim),
   3357        {JS::PropertyAttribute::Configurable, JS::PropertyAttribute::Enumerable,
   3358         JS::PropertyAttribute::Writable})));
   3359    return true;
   3360  }
   3361 #endif
   3362 
   3363  return true;
   3364 }
   3365 
   3366 /* static */
   3367 bool nsGlobalWindowInner::MayResolve(jsid aId) {
   3368  // Note: This function does not fail and may not have any side-effects.
   3369  // Note: Keep this in sync with DoResolve.
   3370  if (!aId.isString()) {
   3371    return false;
   3372  }
   3373 
   3374  if (aId == XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_COMPONENTS)) {
   3375    return true;
   3376  }
   3377 
   3378  if (aId == XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_CONTROLLERS) ||
   3379      aId == XPCJSRuntime::Get()->GetStringID(
   3380                 XPCJSContext::IDX_CONTROLLERS_CLASS)) {
   3381    // We only resolve .controllers/.Controllers in release builds and on
   3382    // non-chrome windows, but let's not worry about any of that stuff.
   3383    return true;
   3384  }
   3385 
   3386  return WebIDLGlobalNameHash::MayResolve(aId);
   3387 }
   3388 
   3389 void nsGlobalWindowInner::GetOwnPropertyNames(
   3390    JSContext* aCx, JS::MutableHandleVector<jsid> aNames, bool aEnumerableOnly,
   3391    ErrorResult& aRv) {
   3392  if (aEnumerableOnly) {
   3393    // The names we would return from here get defined on the window via one of
   3394    // two codepaths.  The ones coming from the WebIDLGlobalNameHash will end up
   3395    // in the DefineConstructor function in BindingUtils, which always defines
   3396    // things as non-enumerable.  The ones coming from the script namespace
   3397    // manager get defined by our resolve hook using FillPropertyDescriptor with
   3398    // 0 for the property attributes, so non-enumerable as well.
   3399    //
   3400    // So in the aEnumerableOnly case we have nothing to do.
   3401    return;
   3402  }
   3403 
   3404  // "Components" is marked as enumerable but only resolved on demand :-/.
   3405  // aNames.AppendElement(u"Components"_ns);
   3406 
   3407  JS::Rooted<JSObject*> wrapper(aCx, GetWrapper());
   3408 
   3409  // There are actually two ways we can get called here: For normal
   3410  // enumeration or for Xray enumeration.  In the latter case, we want to
   3411  // return all possible WebIDL names, because we don't really support
   3412  // deleting these names off our Xray; trying to resolve them will just make
   3413  // them come back.  In the former case, we want to avoid returning deleted
   3414  // names.  But the JS engine already knows about the non-deleted
   3415  // already-resolved names, so we can just return the so-far-unresolved ones.
   3416  //
   3417  // We can tell which case we're in by whether aCx is in our wrapper's
   3418  // compartment.  If not, we're in the Xray case.
   3419  WebIDLGlobalNameHash::NameType nameType =
   3420      js::IsObjectInContextCompartment(wrapper, aCx)
   3421          ? WebIDLGlobalNameHash::UnresolvedNamesOnly
   3422          : WebIDLGlobalNameHash::AllNames;
   3423  if (!WebIDLGlobalNameHash::GetNames(aCx, wrapper, nameType, aNames)) {
   3424    aRv.NoteJSContextException(aCx);
   3425  }
   3426 }
   3427 
   3428 /* static */
   3429 bool nsGlobalWindowInner::IsPrivilegedChromeWindow(JSContext*, JSObject* aObj) {
   3430  // For now, have to deal with XPConnect objects here.
   3431  nsGlobalWindowInner* win = xpc::WindowOrNull(aObj);
   3432  return win && win->IsChromeWindow() &&
   3433         nsContentUtils::ObjectPrincipal(aObj) ==
   3434             nsContentUtils::GetSystemPrincipal();
   3435 }
   3436 
   3437 /* static */
   3438 bool nsGlobalWindowInner::DeviceSensorsEnabled(JSContext*, JSObject*) {
   3439  return Preferences::GetBool("device.sensors.enabled");
   3440 }
   3441 
   3442 Crypto* nsGlobalWindowInner::GetCrypto(ErrorResult& aError) {
   3443  if (!mCrypto) {
   3444    mCrypto = new Crypto(this);
   3445  }
   3446  return mCrypto;
   3447 }
   3448 
   3449 nsIControllers* nsGlobalWindowInner::GetControllers(ErrorResult& aError) {
   3450  FORWARD_TO_OUTER_OR_THROW(GetControllersOuter, (aError), aError, nullptr);
   3451 }
   3452 
   3453 nsresult nsGlobalWindowInner::GetControllers(nsIControllers** aResult) {
   3454  ErrorResult rv;
   3455  nsCOMPtr<nsIControllers> controllers = GetControllers(rv);
   3456  controllers.forget(aResult);
   3457 
   3458  return rv.StealNSResult();
   3459 }
   3460 
   3461 Nullable<WindowProxyHolder> nsGlobalWindowInner::GetOpenerWindow(
   3462    ErrorResult& aError) {
   3463  FORWARD_TO_OUTER_OR_THROW(GetOpenerWindowOuter, (), aError, nullptr);
   3464 }
   3465 
   3466 void nsGlobalWindowInner::GetOpener(JSContext* aCx,
   3467                                    JS::MutableHandle<JS::Value> aRetval,
   3468                                    ErrorResult& aError) {
   3469  Nullable<WindowProxyHolder> opener = GetOpenerWindow(aError);
   3470  if (aError.Failed() || opener.IsNull()) {
   3471    aRetval.setNull();
   3472    return;
   3473  }
   3474 
   3475  if (!ToJSValue(aCx, opener.Value(), aRetval)) {
   3476    aError.NoteJSContextException(aCx);
   3477  }
   3478 }
   3479 
   3480 void nsGlobalWindowInner::SetOpener(JSContext* aCx,
   3481                                    JS::Handle<JS::Value> aOpener,
   3482                                    ErrorResult& aError) {
   3483  if (aOpener.isNull()) {
   3484    RefPtr<BrowsingContext> bc(GetBrowsingContext());
   3485    if (!bc->IsDiscarded()) {
   3486      bc->SetOpener(nullptr);
   3487    }
   3488    return;
   3489  }
   3490 
   3491  // If something other than null is passed, just define aOpener on our inner
   3492  // window's JS object, wrapped into the current compartment so that for Xrays
   3493  // we define on the Xray expando object, but don't set it on the outer window,
   3494  // so that it'll get reset on navigation.  This is just like replaceable
   3495  // properties, but we're not quite readonly.
   3496  RedefineProperty(aCx, "opener", aOpener, aError);
   3497 }
   3498 
   3499 void nsGlobalWindowInner::GetEvent(OwningEventOrUndefined& aRetval) {
   3500  if (mEvent) {
   3501    aRetval.SetAsEvent() = mEvent;
   3502  } else {
   3503    aRetval.SetUndefined();
   3504  }
   3505 }
   3506 
   3507 void nsGlobalWindowInner::GetStatus(nsAString& aStatus, ErrorResult& aError) {
   3508  FORWARD_TO_OUTER_OR_THROW(GetStatusOuter, (aStatus), aError, );
   3509 }
   3510 
   3511 void nsGlobalWindowInner::SetStatus(const nsAString& aStatus,
   3512                                    ErrorResult& aError) {
   3513  FORWARD_TO_OUTER_OR_THROW(SetStatusOuter, (aStatus), aError, );
   3514 }
   3515 
   3516 void nsGlobalWindowInner::GetName(nsAString& aName, ErrorResult& aError) {
   3517  FORWARD_TO_OUTER_OR_THROW(GetNameOuter, (aName), aError, );
   3518 }
   3519 
   3520 void nsGlobalWindowInner::SetName(const nsAString& aName,
   3521                                  mozilla::ErrorResult& aError) {
   3522  FORWARD_TO_OUTER_OR_THROW(SetNameOuter, (aName, aError), aError, );
   3523 }
   3524 
   3525 double nsGlobalWindowInner::GetInnerWidth(ErrorResult& aError) {
   3526  FORWARD_TO_OUTER_OR_THROW(GetInnerWidthOuter, (aError), aError, 0);
   3527 }
   3528 
   3529 nsresult nsGlobalWindowInner::GetInnerWidth(double* aWidth) {
   3530  ErrorResult rv;
   3531  // Callee doesn't care about the caller type, but play it safe.
   3532  *aWidth = GetInnerWidth(rv);
   3533  return rv.StealNSResult();
   3534 }
   3535 
   3536 double nsGlobalWindowInner::GetInnerHeight(ErrorResult& aError) {
   3537  // We ignore aCallerType; we only have that argument because some other things
   3538  // called by GetReplaceableWindowCoord need it.  If this ever changes, fix
   3539  //   nsresult nsGlobalWindowInner::GetInnerHeight(double* aInnerWidth)
   3540  // to actually take a useful CallerType and pass it in here.
   3541  FORWARD_TO_OUTER_OR_THROW(GetInnerHeightOuter, (aError), aError, 0);
   3542 }
   3543 
   3544 nsresult nsGlobalWindowInner::GetInnerHeight(double* aHeight) {
   3545  ErrorResult rv;
   3546  // Callee doesn't care about the caller type, but play it safe.
   3547  *aHeight = GetInnerHeight(rv);
   3548  return rv.StealNSResult();
   3549 }
   3550 
   3551 int32_t nsGlobalWindowInner::GetOuterWidth(CallerType aCallerType,
   3552                                           ErrorResult& aError) {
   3553  FORWARD_TO_OUTER_OR_THROW(GetOuterWidthOuter, (aCallerType, aError), aError,
   3554                            0);
   3555 }
   3556 
   3557 int32_t nsGlobalWindowInner::GetOuterHeight(CallerType aCallerType,
   3558                                            ErrorResult& aError) {
   3559  FORWARD_TO_OUTER_OR_THROW(GetOuterHeightOuter, (aCallerType, aError), aError,
   3560                            0);
   3561 }
   3562 
   3563 double nsGlobalWindowInner::ScreenEdgeSlopX() const {
   3564  FORWARD_TO_OUTER(ScreenEdgeSlopX, (), 0);
   3565 }
   3566 
   3567 double nsGlobalWindowInner::ScreenEdgeSlopY() const {
   3568  FORWARD_TO_OUTER(ScreenEdgeSlopY, (), 0);
   3569 }
   3570 
   3571 int32_t nsGlobalWindowInner::GetScreenX(CallerType aCallerType,
   3572                                        ErrorResult& aError) {
   3573  FORWARD_TO_OUTER_OR_THROW(GetScreenXOuter, (aCallerType, aError), aError, 0);
   3574 }
   3575 
   3576 int32_t nsGlobalWindowInner::GetScreenY(CallerType aCallerType,
   3577                                        ErrorResult& aError) {
   3578  FORWARD_TO_OUTER_OR_THROW(GetScreenYOuter, (aCallerType, aError), aError, 0);
   3579 }
   3580 
   3581 float nsGlobalWindowInner::GetMozInnerScreenX(CallerType aCallerType,
   3582                                              ErrorResult& aError) {
   3583  FORWARD_TO_OUTER_OR_THROW(GetMozInnerScreenXOuter, (aCallerType), aError, 0);
   3584 }
   3585 
   3586 float nsGlobalWindowInner::GetMozInnerScreenY(CallerType aCallerType,
   3587                                              ErrorResult& aError) {
   3588  FORWARD_TO_OUTER_OR_THROW(GetMozInnerScreenYOuter, (aCallerType), aError, 0);
   3589 }
   3590 
   3591 static nsPresContext* GetPresContextForRatio(Document* aDoc) {
   3592  if (nsPresContext* presContext = aDoc->GetPresContext()) {
   3593    return presContext;
   3594  }
   3595  // We're in an undisplayed subdocument... There's not really an awesome way
   3596  // to tell what the right DPI is from here, so we try to walk up our parent
   3597  // document chain to the extent that the docs can observe each other.
   3598  Document* doc = aDoc;
   3599  while (doc->StyleOrLayoutObservablyDependsOnParentDocumentLayout()) {
   3600    doc = doc->GetInProcessParentDocument();
   3601    if (nsPresContext* presContext = doc->GetPresContext()) {
   3602      return presContext;
   3603    }
   3604  }
   3605  return nullptr;
   3606 }
   3607 
   3608 double nsGlobalWindowInner::GetDevicePixelRatio(CallerType aCallerType,
   3609                                                ErrorResult& aError) {
   3610  ENSURE_ACTIVE_DOCUMENT(aError, 0.0);
   3611 
   3612  RefPtr<nsPresContext> presContext = GetPresContextForRatio(mDoc);
   3613  if (NS_WARN_IF(!presContext)) {
   3614    // Still nothing, oh well.
   3615    return 1.0;
   3616  }
   3617 
   3618  if (nsIGlobalObject::ShouldResistFingerprinting(
   3619          aCallerType, RFPTarget::WindowDevicePixelRatio)) {
   3620    return nsRFPService::GetDevicePixelRatioAtZoom(presContext->GetFullZoom());
   3621  }
   3622 
   3623  if (aCallerType == CallerType::NonSystem) {
   3624    float overrideDPPX = presContext->GetOverrideDPPX();
   3625    if (overrideDPPX > 0.0f) {
   3626      return overrideDPPX;
   3627    }
   3628  }
   3629 
   3630  return double(AppUnitsPerCSSPixel()) /
   3631         double(presContext->AppUnitsPerDevPixel());
   3632 }
   3633 
   3634 double nsGlobalWindowInner::GetDesktopToDeviceScale(ErrorResult& aError) {
   3635  ENSURE_ACTIVE_DOCUMENT(aError, 0.0);
   3636  nsPresContext* presContext = GetPresContextForRatio(mDoc);
   3637  if (!presContext) {
   3638    return 1.0;
   3639  }
   3640  return presContext->DeviceContext()->GetDesktopToDeviceScale().scale;
   3641 }
   3642 
   3643 uint32_t nsGlobalWindowInner::RequestAnimationFrame(
   3644    FrameRequestCallback& aCallback, ErrorResult& aError) {
   3645  if (!mDoc) {
   3646    return 0;
   3647  }
   3648 
   3649  if (GetWrapperPreserveColor()) {
   3650    js::NotifyAnimationActivity(GetWrapperPreserveColor());
   3651  }
   3652 
   3653  DebuggerNotificationDispatch(this,
   3654                               DebuggerNotificationType::RequestAnimationFrame);
   3655 
   3656  uint32_t handle;
   3657  aError = mDoc->ScheduleFrameRequestCallback(aCallback, &handle);
   3658  return handle;
   3659 }
   3660 
   3661 void nsGlobalWindowInner::CancelAnimationFrame(uint32_t aHandle,
   3662                                               ErrorResult& aError) {
   3663  if (!mDoc) {
   3664    return;
   3665  }
   3666 
   3667  DebuggerNotificationDispatch(this,
   3668                               DebuggerNotificationType::CancelAnimationFrame);
   3669 
   3670  mDoc->CancelFrameRequestCallback(aHandle);
   3671 }
   3672 
   3673 already_AddRefed<MediaQueryList> nsGlobalWindowInner::MatchMedia(
   3674    const nsACString& aMediaQueryList, CallerType aCallerType,
   3675    ErrorResult& aError) {
   3676  ENSURE_ACTIVE_DOCUMENT(aError, nullptr);
   3677  return mDoc->MatchMedia(aMediaQueryList, aCallerType);
   3678 }
   3679 
   3680 int32_t nsGlobalWindowInner::GetScrollMinX(ErrorResult& aError) {
   3681  FORWARD_TO_OUTER_OR_THROW(GetScrollBoundaryOuter, (eSideLeft), aError, 0);
   3682 }
   3683 
   3684 int32_t nsGlobalWindowInner::GetScrollMinY(ErrorResult& aError) {
   3685  FORWARD_TO_OUTER_OR_THROW(GetScrollBoundaryOuter, (eSideTop), aError, 0);
   3686 }
   3687 
   3688 int32_t nsGlobalWindowInner::GetScrollMaxX(ErrorResult& aError) {
   3689  FORWARD_TO_OUTER_OR_THROW(GetScrollBoundaryOuter, (eSideRight), aError, 0);
   3690 }
   3691 
   3692 int32_t nsGlobalWindowInner::GetScrollMaxY(ErrorResult& aError) {
   3693  FORWARD_TO_OUTER_OR_THROW(GetScrollBoundaryOuter, (eSideBottom), aError, 0);
   3694 }
   3695 
   3696 double nsGlobalWindowInner::GetScrollX(ErrorResult& aError) {
   3697  FORWARD_TO_OUTER_OR_THROW(GetScrollXOuter, (), aError, 0);
   3698 }
   3699 
   3700 double nsGlobalWindowInner::GetScrollY(ErrorResult& aError) {
   3701  FORWARD_TO_OUTER_OR_THROW(GetScrollYOuter, (), aError, 0);
   3702 }
   3703 
   3704 uint32_t nsGlobalWindowInner::Length() { FORWARD_TO_OUTER(Length, (), 0); }
   3705 
   3706 Nullable<WindowProxyHolder> nsGlobalWindowInner::GetTop(
   3707    mozilla::ErrorResult& aError) {
   3708  FORWARD_TO_OUTER_OR_THROW(GetTopOuter, (), aError, nullptr);
   3709 }
   3710 
   3711 already_AddRefed<BrowsingContext> nsGlobalWindowInner::GetChildWindow(
   3712    const nsAString& aName) {
   3713  if (GetOuterWindowInternal()) {
   3714    return GetOuterWindowInternal()->GetChildWindow(aName);
   3715  }
   3716  return nullptr;
   3717 }
   3718 
   3719 void nsGlobalWindowInner::RefreshRealmPrincipal() {
   3720  JS::SetRealmPrincipals(js::GetNonCCWObjectRealm(GetWrapperPreserveColor()),
   3721                         nsJSPrincipals::get(mDoc->NodePrincipal()));
   3722 }
   3723 
   3724 void nsGlobalWindowInner::RefreshReduceTimerPrecisionCallerType() {
   3725  JS::SetRealmReduceTimerPrecisionCallerType(
   3726      js::GetNonCCWObjectRealm(GetWrapperPreserveColor()),
   3727      RTPCallerTypeToToken(GetRTPCallerType()));
   3728 }
   3729 
   3730 already_AddRefed<nsIWidget> nsGlobalWindowInner::GetMainWidget() const {
   3731  FORWARD_TO_OUTER(GetMainWidget, (), nullptr);
   3732 }
   3733 
   3734 nsIWidget* nsGlobalWindowInner::GetNearestWidget() const {
   3735  if (GetOuterWindowInternal()) {
   3736    return GetOuterWindowInternal()->GetNearestWidget();
   3737  }
   3738  return nullptr;
   3739 }
   3740 
   3741 void nsGlobalWindowInner::SetFullScreen(bool aFullscreen,
   3742                                        mozilla::ErrorResult& aError) {
   3743  FORWARD_TO_OUTER_OR_THROW(SetFullscreenOuter, (aFullscreen, aError), aError,
   3744                            /* void */);
   3745 }
   3746 
   3747 bool nsGlobalWindowInner::GetFullScreen(ErrorResult& aError) {
   3748  FORWARD_TO_OUTER_OR_THROW(GetFullscreenOuter, (), aError, false);
   3749 }
   3750 
   3751 bool nsGlobalWindowInner::GetFullScreen() {
   3752  ErrorResult dummy;
   3753  bool fullscreen = GetFullScreen(dummy);
   3754  dummy.SuppressException();
   3755  return fullscreen;
   3756 }
   3757 
   3758 void nsGlobalWindowInner::Dump(const nsAString& aStr) {
   3759  if (!nsJSUtils::DumpEnabled()) {
   3760    return;
   3761  }
   3762 
   3763  char* cstr = ToNewUTF8String(aStr);
   3764 
   3765 #if defined(XP_MACOSX)
   3766  // have to convert \r to \n so that printing to the console works
   3767  char *c = cstr, *cEnd = cstr + strlen(cstr);
   3768  while (c < cEnd) {
   3769    if (*c == '\r') *c = '\n';
   3770    c++;
   3771  }
   3772 #endif
   3773 
   3774  if (cstr) {
   3775    MOZ_LOG(nsContentUtils::DOMDumpLog(), LogLevel::Debug,
   3776            ("[Window.Dump] %s", cstr));
   3777 #ifdef XP_WIN
   3778    PrintToDebugger(cstr);
   3779 #endif
   3780 #ifdef ANDROID
   3781    __android_log_write(ANDROID_LOG_INFO, "GeckoDump", cstr);
   3782 #endif
   3783    FILE* fp = gDumpFile ? gDumpFile : stdout;
   3784    fputs(cstr, fp);
   3785    fflush(fp);
   3786    free(cstr);
   3787  }
   3788 }
   3789 
   3790 void nsGlobalWindowInner::Alert(nsIPrincipal& aSubjectPrincipal,
   3791                                ErrorResult& aError) {
   3792  Alert(u""_ns, aSubjectPrincipal, aError);
   3793 }
   3794 
   3795 void nsGlobalWindowInner::Alert(const nsAString& aMessage,
   3796                                nsIPrincipal& aSubjectPrincipal,
   3797                                ErrorResult& aError) {
   3798  FORWARD_TO_OUTER_OR_THROW(AlertOuter, (aMessage, aSubjectPrincipal, aError),
   3799                            aError, );
   3800 }
   3801 
   3802 bool nsGlobalWindowInner::Confirm(const nsAString& aMessage,
   3803                                  nsIPrincipal& aSubjectPrincipal,
   3804                                  ErrorResult& aError) {
   3805  FORWARD_TO_OUTER_OR_THROW(ConfirmOuter, (aMessage, aSubjectPrincipal, aError),
   3806                            aError, false);
   3807 }
   3808 
   3809 already_AddRefed<Promise> nsGlobalWindowInner::Fetch(
   3810    const RequestOrUTF8String& aInput, const RequestInit& aInit,
   3811    CallerType aCallerType, ErrorResult& aRv) {
   3812  return FetchRequest(this, aInput, aInit, aCallerType, aRv);
   3813 }
   3814 
   3815 void nsGlobalWindowInner::Prompt(const nsAString& aMessage,
   3816                                 const nsAString& aInitial, nsAString& aReturn,
   3817                                 nsIPrincipal& aSubjectPrincipal,
   3818                                 ErrorResult& aError) {
   3819  FORWARD_TO_OUTER_OR_THROW(
   3820      PromptOuter, (aMessage, aInitial, aReturn, aSubjectPrincipal, aError),
   3821      aError, );
   3822 }
   3823 
   3824 void nsGlobalWindowInner::Focus(CallerType aCallerType, ErrorResult& aError) {
   3825  FORWARD_TO_OUTER_OR_THROW(FocusOuter,
   3826                            (aCallerType, /* aFromOtherProcess */ false,
   3827                             nsFocusManager::GenerateFocusActionId()),
   3828                            aError, );
   3829 }
   3830 
   3831 nsresult nsGlobalWindowInner::Focus(CallerType aCallerType) {
   3832  ErrorResult rv;
   3833  Focus(aCallerType, rv);
   3834 
   3835  return rv.StealNSResult();
   3836 }
   3837 
   3838 void nsGlobalWindowInner::Blur(CallerType aCallerType, ErrorResult& aError) {
   3839  FORWARD_TO_OUTER_OR_THROW(BlurOuter, (aCallerType), aError, );
   3840 }
   3841 
   3842 void nsGlobalWindowInner::Stop(ErrorResult& aError) {
   3843  FORWARD_TO_OUTER_OR_THROW(StopOuter, (aError), aError, );
   3844 }
   3845 
   3846 void nsGlobalWindowInner::Print(ErrorResult& aError) {
   3847  FORWARD_TO_OUTER_OR_THROW(PrintOuter, (aError), aError, );
   3848 }
   3849 
   3850 Nullable<WindowProxyHolder> nsGlobalWindowInner::PrintPreview(
   3851    nsIPrintSettings* aSettings, nsIWebProgressListener* aListener,
   3852    nsIDocShell* aDocShellToCloneInto, ErrorResult& aError) {
   3853  FORWARD_TO_OUTER_OR_THROW(
   3854      Print,
   3855      (aSettings,
   3856       /* aRemotePrintJob = */ nullptr, aListener, aDocShellToCloneInto,
   3857       nsGlobalWindowOuter::IsPreview::Yes,
   3858       nsGlobalWindowOuter::IsForWindowDotPrint::No,
   3859       /* aPrintPreviewCallback = */ nullptr, nullptr, aError),
   3860      aError, nullptr);
   3861 }
   3862 
   3863 void nsGlobalWindowInner::MoveTo(int32_t aXPos, int32_t aYPos,
   3864                                 CallerType aCallerType, ErrorResult& aError) {
   3865  FORWARD_TO_OUTER_OR_THROW(MoveToOuter, (aXPos, aYPos, aCallerType, aError),
   3866                            aError, );
   3867 }
   3868 
   3869 void nsGlobalWindowInner::MoveBy(int32_t aXDif, int32_t aYDif,
   3870                                 CallerType aCallerType, ErrorResult& aError) {
   3871  FORWARD_TO_OUTER_OR_THROW(MoveByOuter, (aXDif, aYDif, aCallerType, aError),
   3872                            aError, );
   3873 }
   3874 
   3875 void nsGlobalWindowInner::ResizeTo(int32_t aWidth, int32_t aHeight,
   3876                                   CallerType aCallerType,
   3877                                   ErrorResult& aError) {
   3878  FORWARD_TO_OUTER_OR_THROW(ResizeToOuter,
   3879                            (aWidth, aHeight, aCallerType, aError), aError, );
   3880 }
   3881 
   3882 void nsGlobalWindowInner::ResizeBy(int32_t aWidthDif, int32_t aHeightDif,
   3883                                   CallerType aCallerType,
   3884                                   ErrorResult& aError) {
   3885  FORWARD_TO_OUTER_OR_THROW(
   3886      ResizeByOuter, (aWidthDif, aHeightDif, aCallerType, aError), aError, );
   3887 }
   3888 
   3889 void nsGlobalWindowInner::SizeToContent(
   3890    const SizeToContentConstraints& aConstraints, ErrorResult& aError) {
   3891  FORWARD_TO_OUTER_OR_THROW(SizeToContentOuter, (aConstraints, aError),
   3892                            aError, );
   3893 }
   3894 
   3895 already_AddRefed<nsPIWindowRoot> nsGlobalWindowInner::GetTopWindowRoot() {
   3896  nsGlobalWindowOuter* outer = GetOuterWindowInternal();
   3897  if (!outer) {
   3898    return nullptr;
   3899  }
   3900  return outer->GetTopWindowRoot();
   3901 }
   3902 
   3903 void nsGlobalWindowInner::ScrollTo(double aXScroll, double aYScroll) {
   3904  ScrollToOptions options;
   3905  options.mLeft.Construct(aXScroll);
   3906  options.mTop.Construct(aYScroll);
   3907  ScrollTo(options);
   3908 }
   3909 
   3910 void nsGlobalWindowInner::ScrollTo(const ScrollToOptions& aOptions) {
   3911  Maybe<double> left;
   3912  Maybe<double> top;
   3913  if (aOptions.mLeft.WasPassed()) {
   3914    left.emplace(ToZeroIfNonfinite(aOptions.mLeft.Value()));
   3915  }
   3916  if (aOptions.mTop.WasPassed()) {
   3917    top.emplace(ToZeroIfNonfinite(aOptions.mTop.Value()));
   3918  }
   3919 
   3920  // When scrolling to a non-zero offset, we need to determine whether that
   3921  // position is within our scrollable range, so we need updated layout
   3922  // information.
   3923  if ((top && *top != 0) || (left && *left != 0)) {
   3924    FlushPendingNotifications(FlushType::Layout);
   3925  }
   3926 
   3927  ScrollContainerFrame* sf = GetScrollContainerFrame();
   3928  if (!sf) {
   3929    return;
   3930  }
   3931  CSSPoint scrollPos = sf->GetScrollPositionCSSPixels();
   3932  if (left) {
   3933    scrollPos.x = *left;
   3934  }
   3935  if (top) {
   3936    scrollPos.y = *top;
   3937  }
   3938  // Here we calculate what the max pixel value is that we can
   3939  // scroll to, we do this by dividing maxint with the pixel to
   3940  // twips conversion factor, and subtracting 4, the 4 comes from
   3941  // experimenting with this value, anything less makes the view
   3942  // code not scroll correctly, I have no idea why. -- jst
   3943  //
   3944  // FIXME(emilio): This seems like if needed it should be done by the
   3945  // scrolling code itself...
   3946  const double maxpx = CSSPixel::FromAppUnits(0x7fffffff) - 4;
   3947  if (scrollPos.x > maxpx) {
   3948    scrollPos.x = maxpx;
   3949  }
   3950  if (scrollPos.y > maxpx) {
   3951    scrollPos.y = maxpx;
   3952  }
   3953  auto scrollMode = sf->ScrollModeForScrollBehavior(aOptions.mBehavior);
   3954  sf->ScrollToCSSPixels(scrollPos, scrollMode);
   3955 }
   3956 
   3957 void nsGlobalWindowInner::ScrollBy(double aXScrollDif, double aYScrollDif) {
   3958  ScrollToOptions options;
   3959  options.mLeft.Construct(aXScrollDif);
   3960  options.mTop.Construct(aYScrollDif);
   3961  // It seems like it would make more sense for ScrollBy to use
   3962  // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
   3963  // Perhaps Web content does too.
   3964  ScrollBy(options);
   3965 }
   3966 
   3967 void nsGlobalWindowInner::ScrollBy(const ScrollToOptions& aOptions) {
   3968  CSSPoint scrollDelta;
   3969  if (aOptions.mLeft.WasPassed()) {
   3970    scrollDelta.x = ToZeroIfNonfinite(aOptions.mLeft.Value());
   3971  }
   3972  if (aOptions.mTop.WasPassed()) {
   3973    scrollDelta.y = ToZeroIfNonfinite(aOptions.mTop.Value());
   3974  }
   3975 
   3976  if (!scrollDelta.x && !scrollDelta.y) {
   3977    return;
   3978  }
   3979 
   3980  FlushPendingNotifications(FlushType::Layout);
   3981  ScrollContainerFrame* sf = GetScrollContainerFrame();
   3982  if (!sf) {
   3983    return;
   3984  }
   3985 
   3986  auto scrollMode = sf->ScrollModeForScrollBehavior(aOptions.mBehavior);
   3987  sf->ScrollByCSSPixels(scrollDelta, scrollMode);
   3988 }
   3989 
   3990 void nsGlobalWindowInner::ScrollByLines(int32_t numLines,
   3991                                        const ScrollOptions& aOptions) {
   3992  if (!numLines) {
   3993    return;
   3994  }
   3995  FlushPendingNotifications(FlushType::Layout);
   3996  ScrollContainerFrame* sf = GetScrollContainerFrame();
   3997  if (!sf) {
   3998    return;
   3999  }
   4000  // It seems like it would make more sense for ScrollByLines to use
   4001  // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
   4002  // Perhaps Web content does too.
   4003  ScrollMode scrollMode = sf->ScrollModeForScrollBehavior(aOptions.mBehavior);
   4004  sf->ScrollBy(nsIntPoint(0, numLines), ScrollUnit::LINES, scrollMode);
   4005 }
   4006 
   4007 void nsGlobalWindowInner::ScrollByPages(int32_t numPages,
   4008                                        const ScrollOptions& aOptions) {
   4009  if (!numPages) {
   4010    return;
   4011  }
   4012  FlushPendingNotifications(FlushType::Layout);
   4013  ScrollContainerFrame* sf = GetScrollContainerFrame();
   4014  if (!sf) {
   4015    return;
   4016  }
   4017  // It seems like it would make more sense for ScrollByPages to use
   4018  // SMOOTH mode, but tests seem to depend on the synchronous behaviour.
   4019  // Perhaps Web content does too.
   4020  ScrollMode scrollMode = sf->ScrollModeForScrollBehavior(aOptions.mBehavior);
   4021 
   4022  sf->ScrollBy(nsIntPoint(0, numPages), ScrollUnit::PAGES, scrollMode);
   4023 }
   4024 
   4025 void nsGlobalWindowInner::MozScrollSnap() {
   4026  FlushPendingNotifications(FlushType::Layout);
   4027  if (ScrollContainerFrame* sf = GetScrollContainerFrame()) {
   4028    sf->ScrollSnap();
   4029  }
   4030 }
   4031 
   4032 void nsGlobalWindowInner::ClearTimeout(int32_t aHandle) {
   4033  DebuggerNotificationDispatch(this, DebuggerNotificationType::ClearTimeout);
   4034 
   4035  if (aHandle > 0) {
   4036    mTimeoutManager->ClearTimeout(aHandle, Timeout::Reason::eTimeoutOrInterval);
   4037  }
   4038 }
   4039 
   4040 void nsGlobalWindowInner::ClearInterval(int32_t aHandle) {
   4041  DebuggerNotificationDispatch(this, DebuggerNotificationType::ClearInterval);
   4042 
   4043  if (aHandle > 0) {
   4044    mTimeoutManager->ClearTimeout(aHandle, Timeout::Reason::eTimeoutOrInterval);
   4045  }
   4046 }
   4047 
   4048 void nsGlobalWindowInner::SetResizable(bool aResizable) const {
   4049  // nop
   4050 }
   4051 
   4052 void nsGlobalWindowInner::CaptureEvents() {
   4053  if (mDoc) {
   4054    mDoc->WarnOnceAbout(DeprecatedOperations::eUseOfCaptureEvents);
   4055  }
   4056 }
   4057 
   4058 void nsGlobalWindowInner::ReleaseEvents() {
   4059  if (mDoc) {
   4060    mDoc->WarnOnceAbout(DeprecatedOperations::eUseOfReleaseEvents);
   4061  }
   4062 }
   4063 
   4064 Nullable<WindowProxyHolder> nsGlobalWindowInner::Open(const nsAString& aUrl,
   4065                                                      const nsAString& aName,
   4066                                                      const nsAString& aOptions,
   4067                                                      ErrorResult& aError) {
   4068  FORWARD_TO_OUTER_OR_THROW(OpenOuter, (aUrl, aName, aOptions, aError), aError,
   4069                            nullptr);
   4070 }
   4071 
   4072 Nullable<WindowProxyHolder> nsGlobalWindowInner::OpenDialog(
   4073    JSContext* aCx, const nsAString& aUrl, const nsAString& aName,
   4074    const nsAString& aOptions, const Sequence<JS::Value>& aExtraArgument,
   4075    ErrorResult& aError) {
   4076  FORWARD_TO_OUTER_OR_THROW(
   4077      OpenDialogOuter, (aCx, aUrl, aName, aOptions, aExtraArgument, aError),
   4078      aError, nullptr);
   4079 }
   4080 
   4081 WindowProxyHolder nsGlobalWindowInner::GetFrames(ErrorResult& aError) {
   4082  FORWARD_TO_OUTER_OR_THROW(GetFramesOuter, (), aError, Window());
   4083 }
   4084 
   4085 void nsGlobalWindowInner::PostMessageMoz(JSContext* aCx,
   4086                                         JS::Handle<JS::Value> aMessage,
   4087                                         const nsAString& aTargetOrigin,
   4088                                         JS::Handle<JS::Value> aTransfer,
   4089                                         nsIPrincipal& aSubjectPrincipal,
   4090                                         ErrorResult& aError) {
   4091  FORWARD_TO_OUTER_OR_THROW(
   4092      PostMessageMozOuter,
   4093      (aCx, aMessage, aTargetOrigin, aTransfer, aSubjectPrincipal, aError),
   4094      aError, );
   4095 }
   4096 
   4097 void nsGlobalWindowInner::PostMessageMoz(JSContext* aCx,
   4098                                         JS::Handle<JS::Value> aMessage,
   4099                                         const nsAString& aTargetOrigin,
   4100                                         const Sequence<JSObject*>& aTransfer,
   4101                                         nsIPrincipal& aSubjectPrincipal,
   4102                                         ErrorResult& aRv) {
   4103  JS::Rooted<JS::Value> transferArray(aCx, JS::UndefinedValue());
   4104 
   4105  aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransfer,
   4106                                                          &transferArray);
   4107  if (NS_WARN_IF(aRv.Failed())) {
   4108    return;
   4109  }
   4110 
   4111  PostMessageMoz(aCx, aMessage, aTargetOrigin, transferArray, aSubjectPrincipal,
   4112                 aRv);
   4113 }
   4114 
   4115 void nsGlobalWindowInner::PostMessageMoz(
   4116    JSContext* aCx, JS::Handle<JS::Value> aMessage,
   4117    const WindowPostMessageOptions& aOptions, nsIPrincipal& aSubjectPrincipal,
   4118    ErrorResult& aRv) {
   4119  JS::Rooted<JS::Value> transferArray(aCx, JS::UndefinedValue());
   4120 
   4121  aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(
   4122      aCx, aOptions.mTransfer, &transferArray);
   4123  if (NS_WARN_IF(aRv.Failed())) {
   4124    return;
   4125  }
   4126 
   4127  PostMessageMoz(aCx, aMessage, aOptions.mTargetOrigin, transferArray,
   4128                 aSubjectPrincipal, aRv);
   4129 }
   4130 
   4131 void nsGlobalWindowInner::Close(CallerType aCallerType, ErrorResult& aError) {
   4132  FORWARD_TO_OUTER_OR_THROW(CloseOuter, (aCallerType == CallerType::System),
   4133                            aError, );
   4134 }
   4135 
   4136 nsresult nsGlobalWindowInner::Close() {
   4137  FORWARD_TO_OUTER(Close, (), NS_ERROR_UNEXPECTED);
   4138 }
   4139 
   4140 bool nsGlobalWindowInner::IsInModalState() {
   4141  FORWARD_TO_OUTER(IsInModalState, (), false);
   4142 }
   4143 
   4144 void nsGlobalWindowInner::NotifyWindowIDDestroyed(const char* aTopic) {
   4145  nsCOMPtr<nsIRunnable> runnable =
   4146      new WindowDestroyedEvent(this, mWindowID, aTopic);
   4147  Dispatch(runnable.forget());
   4148 }
   4149 
   4150 Element* nsGlobalWindowInner::GetFrameElement(nsIPrincipal& aSubjectPrincipal,
   4151                                              ErrorResult& aError) {
   4152  FORWARD_TO_OUTER_OR_THROW(GetFrameElement, (aSubjectPrincipal), aError,
   4153                            nullptr);
   4154 }
   4155 
   4156 Element* nsGlobalWindowInner::GetRealFrameElement(ErrorResult& aError) {
   4157  FORWARD_TO_OUTER_OR_THROW(GetFrameElement, (), aError, nullptr);
   4158 }
   4159 
   4160 void nsGlobalWindowInner::UpdateCommands(const nsAString& anAction) {
   4161  if (GetOuterWindowInternal()) {
   4162    GetOuterWindowInternal()->UpdateCommands(anAction);
   4163  }
   4164 }
   4165 
   4166 Selection* nsGlobalWindowInner::GetSelection(ErrorResult& aError) {
   4167  FORWARD_TO_OUTER_OR_THROW(GetSelectionOuter, (), aError, nullptr);
   4168 }
   4169 
   4170 WebTaskScheduler* nsGlobalWindowInner::Scheduler() {
   4171  if (!mWebTaskScheduler) {
   4172    mWebTaskScheduler = WebTaskScheduler::CreateForMainThread(this);
   4173  }
   4174  MOZ_ASSERT(mWebTaskScheduler);
   4175  return mWebTaskScheduler;
   4176 }
   4177 
   4178 inline void nsGlobalWindowInner::SetWebTaskSchedulingState(
   4179    WebTaskSchedulingState* aState) {
   4180  mWebTaskSchedulingState = aState;
   4181 }
   4182 
   4183 bool nsGlobalWindowInner::Find(const nsAString& aString, bool aCaseSensitive,
   4184                               bool aBackwards, bool aWrapAround,
   4185                               bool aWholeWord, bool aSearchInFrames,
   4186                               bool aShowDialog, ErrorResult& aError) {
   4187  FORWARD_TO_OUTER_OR_THROW(FindOuter,
   4188                            (aString, aCaseSensitive, aBackwards, aWrapAround,
   4189                             aWholeWord, aSearchInFrames, aShowDialog, aError),
   4190                            aError, false);
   4191 }
   4192 
   4193 void nsGlobalWindowInner::GetOrigin(nsAString& aOrigin) {
   4194  nsContentUtils::GetWebExposedOriginSerialization(GetPrincipal(), aOrigin);
   4195 }
   4196 
   4197 // See also AutoJSAPI::ReportException
   4198 void nsGlobalWindowInner::ReportError(JSContext* aCx,
   4199                                      JS::Handle<JS::Value> aError,
   4200                                      CallerType aCallerType,
   4201                                      ErrorResult& aRv) {
   4202  if (MOZ_UNLIKELY(!HasActiveDocument())) {
   4203    return aRv.Throw(NS_ERROR_XPC_SECURITY_MANAGER_VETO);
   4204  }
   4205 
   4206  JS::ErrorReportBuilder jsReport(aCx);
   4207  JS::ExceptionStack exnStack(aCx, aError, nullptr);
   4208  if (!jsReport.init(aCx, exnStack, JS::ErrorReportBuilder::NoSideEffects)) {
   4209    return aRv.NoteJSContextException(aCx);
   4210  }
   4211 
   4212  RefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
   4213  bool isChrome = aCallerType == CallerType::System;
   4214  xpcReport->Init(jsReport.report(), jsReport.toStringResult().c_str(),
   4215                  isChrome, WindowID());
   4216 
   4217  JS::RootingContext* rcx = JS::RootingContext::get(aCx);
   4218  DispatchScriptErrorEvent(this, rcx, xpcReport, exnStack.exception(),
   4219                           exnStack.stack());
   4220 }
   4221 
   4222 void nsGlobalWindowInner::Atob(const nsAString& aAsciiBase64String,
   4223                               nsAString& aBinaryData, ErrorResult& aError) {
   4224  aError = nsContentUtils::Atob(aAsciiBase64String, aBinaryData);
   4225 }
   4226 
   4227 void nsGlobalWindowInner::Btoa(const nsAString& aBinaryData,
   4228                               nsAString& aAsciiBase64String,
   4229                               ErrorResult& aError) {
   4230  aError = nsContentUtils::Btoa(aBinaryData, aAsciiBase64String);
   4231 }
   4232 
   4233 //*****************************************************************************
   4234 // EventTarget
   4235 //*****************************************************************************
   4236 
   4237 nsPIDOMWindowOuter* nsGlobalWindowInner::GetOwnerGlobalForBindingsInternal() {
   4238  return nsPIDOMWindowOuter::GetFromCurrentInner(this);
   4239 }
   4240 
   4241 bool nsGlobalWindowInner::DispatchEvent(Event& aEvent, CallerType aCallerType,
   4242                                        ErrorResult& aRv) {
   4243  if (!IsCurrentInnerWindow()) {
   4244    NS_WARNING(
   4245        "DispatchEvent called on non-current inner window, dropping. "
   4246        "Please check the window in the caller instead.");
   4247    aRv.Throw(NS_ERROR_FAILURE);
   4248    return false;
   4249  }
   4250 
   4251  if (!mDoc) {
   4252    aRv.Throw(NS_ERROR_FAILURE);
   4253    return false;
   4254  }
   4255 
   4256  // Obtain a presentation shell
   4257  RefPtr<nsPresContext> presContext = mDoc->GetPresContext();
   4258 
   4259  nsEventStatus status = nsEventStatus_eIgnore;
   4260  nsresult rv = EventDispatcher::DispatchDOMEvent(this, nullptr, &aEvent,
   4261                                                  presContext, &status);
   4262  bool retval = !aEvent.DefaultPrevented(aCallerType);
   4263  if (NS_FAILED(rv)) {
   4264    aRv.Throw(rv);
   4265  }
   4266  return retval;
   4267 }
   4268 
   4269 mozilla::Maybe<mozilla::dom::EventCallbackDebuggerNotificationType>
   4270 nsGlobalWindowInner::GetDebuggerNotificationType() const {
   4271  return mozilla::Some(
   4272      mozilla::dom::EventCallbackDebuggerNotificationType::Global);
   4273 }
   4274 
   4275 bool nsGlobalWindowInner::ComputeDefaultWantsUntrusted(ErrorResult& aRv) {
   4276  return !nsContentUtils::IsChromeDoc(mDoc);
   4277 }
   4278 
   4279 EventListenerManager* nsGlobalWindowInner::GetOrCreateListenerManager() {
   4280  if (!mListenerManager) {
   4281    mListenerManager =
   4282        new EventListenerManager(static_cast<EventTarget*>(this));
   4283  }
   4284 
   4285  return mListenerManager;
   4286 }
   4287 
   4288 EventListenerManager* nsGlobalWindowInner::GetExistingListenerManager() const {
   4289  return mListenerManager;
   4290 }
   4291 
   4292 mozilla::dom::DebuggerNotificationManager*
   4293 nsGlobalWindowInner::GetOrCreateDebuggerNotificationManager() {
   4294  if (!mDebuggerNotificationManager) {
   4295    mDebuggerNotificationManager = new DebuggerNotificationManager(this);
   4296  }
   4297 
   4298  return mDebuggerNotificationManager;
   4299 }
   4300 
   4301 mozilla::dom::DebuggerNotificationManager*
   4302 nsGlobalWindowInner::GetExistingDebuggerNotificationManager() {
   4303  return mDebuggerNotificationManager;
   4304 }
   4305 
   4306 //*****************************************************************************
   4307 // nsGlobalWindowInner::nsPIDOMWindow
   4308 //*****************************************************************************
   4309 
   4310 Location* nsGlobalWindowInner::Location() {
   4311  if (!mLocation) {
   4312    mLocation = new dom::Location(this);
   4313  }
   4314 
   4315  return mLocation;
   4316 }
   4317 
   4318 void nsGlobalWindowInner::MaybeUpdateTouchState() {
   4319  if (mMayHaveTouchEventListener) {
   4320    nsCOMPtr<nsIObserverService> observerService =
   4321        services::GetObserverService();
   4322 
   4323    if (observerService) {
   4324      observerService->NotifyObservers(static_cast<nsIDOMWindow*>(this),
   4325                                       DOM_TOUCH_LISTENER_ADDED, nullptr);
   4326    }
   4327  }
   4328 }
   4329 
   4330 void nsGlobalWindowInner::EnableGamepadUpdates() {
   4331  if (mHasGamepad) {
   4332    RefPtr<GamepadManager> gamepadManager(GamepadManager::GetService());
   4333    if (gamepadManager) {
   4334      gamepadManager->AddListener(this);
   4335    }
   4336  }
   4337 }
   4338 
   4339 void nsGlobalWindowInner::DisableGamepadUpdates() {
   4340  if (mHasGamepad) {
   4341    RefPtr<GamepadManager> gamepadManager(GamepadManager::GetService());
   4342    if (gamepadManager) {
   4343      gamepadManager->RemoveListener(this);
   4344    }
   4345  }
   4346 }
   4347 
   4348 void nsGlobalWindowInner::EnableVRUpdates() {
   4349  // We need to create a VREventObserver before we can either detect XR runtimes
   4350  // or start an XR session
   4351  if (!mVREventObserver && (mHasXRSession || mXRRuntimeDetectionInFlight)) {
   4352    // Assert that we are not creating the observer while IsDying() as
   4353    // that would result in a leak.  VREventObserver holds a RefPtr to
   4354    // this nsGlobalWindowInner and would prevent it from being deallocated.
   4355    MOZ_ASSERT(!IsDying(),
   4356               "Creating a VREventObserver for an nsGlobalWindow that is "
   4357               "dying would cause it to leak.");
   4358    mVREventObserver = new VREventObserver(this);
   4359  }
   4360  // If the content has an XR session, then we need to tell
   4361  // VREventObserver that there is VR activity.
   4362  if (mHasXRSession) {
   4363    nsPIDOMWindowOuter* outer = GetOuterWindow();
   4364    if (outer && !outer->IsBackground()) {
   4365      StartVRActivity();
   4366    }
   4367  }
   4368 }
   4369 
   4370 void nsGlobalWindowInner::DisableVRUpdates() {
   4371  if (mVREventObserver) {
   4372    mVREventObserver->DisconnectFromOwner();
   4373    mVREventObserver = nullptr;
   4374  }
   4375 }
   4376 
   4377 void nsGlobalWindowInner::StartVRActivity() {
   4378  /**
   4379   * If the content has an XR session, tell
   4380   * the VREventObserver that the window is accessing
   4381   * VR devices.
   4382   *
   4383   * It's possible to have a VREventObserver without
   4384   * and XR session, if we are using it to get updates
   4385   * about XR runtime enumeration.  In this case,
   4386   * we would not tell the VREventObserver that
   4387   * we are accessing VR devices.
   4388   */
   4389  if (mVREventObserver && mHasXRSession) {
   4390    mVREventObserver->StartActivity();
   4391  }
   4392 }
   4393 
   4394 void nsGlobalWindowInner::StopVRActivity() {
   4395  /**
   4396   * If the content has an XR session, tell
   4397   * the VReventObserver that the window is no longer
   4398   * accessing VR devices.  This does not stop the
   4399   * XR session itself, which may be resumed with
   4400   * EnableVRUpdates.
   4401   * It's possible to have a VREventObserver without
   4402   * and XR session, if we are using it to get updates
   4403   * about XR runtime enumeration.  In this case,
   4404   * we would not tell the VREventObserver that
   4405   * we ending an activity that accesses VR devices.
   4406   */
   4407  if (mVREventObserver && mHasXRSession) {
   4408    mVREventObserver->StopActivity();
   4409  }
   4410 }
   4411 
   4412 void nsGlobalWindowInner::SetFocusedElement(Element* aElement,
   4413                                            uint32_t aFocusMethod,
   4414                                            bool aNeedsFocus) {
   4415  if (aElement && aElement->GetComposedDoc() != mDoc) {
   4416    NS_WARNING("Trying to set focus to a node from a wrong document");
   4417    return;
   4418  }
   4419 
   4420  if (IsDying()) {
   4421    NS_ASSERTION(!aElement, "Trying to focus cleaned up window!");
   4422    aElement = nullptr;
   4423    aNeedsFocus = false;
   4424  }
   4425  if (mFocusedElement != aElement) {
   4426    mFocusedElement = aElement;
   4427    // TODO: Maybe this should be set on refocus too?
   4428    mFocusMethod = aFocusMethod & nsIFocusManager::METHOD_MASK;
   4429  }
   4430 
   4431  if (mFocusedElement) {
   4432    // if a node was focused by a keypress, turn on focus rings for the
   4433    // window.
   4434    if (mFocusMethod & nsIFocusManager::FLAG_BYKEY) {
   4435      mUnknownFocusMethodShouldShowOutline = true;
   4436      mFocusByKeyOccurred = true;
   4437    } else if (nsFocusManager::GetFocusMoveActionCause(mFocusMethod) !=
   4438               widget::InputContextAction::CAUSE_UNKNOWN) {
   4439      mUnknownFocusMethodShouldShowOutline = false;
   4440    } else if (aFocusMethod & nsIFocusManager::FLAG_NOSHOWRING) {
   4441      // If we get focused via script, and script has explicitly opted out of
   4442      // outlines via FLAG_NOSHOWRING, we don't want to make a refocus start
   4443      // showing outlines.
   4444      mUnknownFocusMethodShouldShowOutline = false;
   4445    }
   4446  }
   4447 
   4448  if (aNeedsFocus) {
   4449    mNeedsFocus = aNeedsFocus;
   4450  }
   4451 }
   4452 
   4453 uint32_t nsGlobalWindowInner::GetFocusMethod() { return mFocusMethod; }
   4454 
   4455 bool nsGlobalWindowInner::ShouldShowFocusRing() {
   4456  if (mFocusByKeyOccurred &&
   4457      StaticPrefs::browser_display_always_show_rings_after_key_focus()) {
   4458    return true;
   4459  }
   4460  return StaticPrefs::browser_display_show_focus_rings();
   4461 }
   4462 
   4463 bool nsGlobalWindowInner::TakeFocus(bool aFocus, uint32_t aFocusMethod) {
   4464  if (IsDying()) {
   4465    return false;
   4466  }
   4467 
   4468  if (aFocus) {
   4469    mFocusMethod = aFocusMethod & nsIFocusManager::METHOD_MASK;
   4470  }
   4471 
   4472  // if mNeedsFocus is true, then the document has not yet received a
   4473  // document-level focus event. If there is a root content node, then return
   4474  // true to tell the calling focus manager that a focus event is expected. If
   4475  // there is no root content node, the document hasn't loaded enough yet, or
   4476  // there isn't one and there is no point in firing a focus event.
   4477  if (aFocus && mNeedsFocus && mDoc && mDoc->GetRootElement()) {
   4478    mNeedsFocus = false;
   4479    return true;
   4480  }
   4481 
   4482  mNeedsFocus = false;
   4483  return false;
   4484 }
   4485 
   4486 void nsGlobalWindowInner::SetReadyForFocus() {
   4487  bool oldNeedsFocus = mNeedsFocus;
   4488  mNeedsFocus = false;
   4489 
   4490  if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
   4491    nsCOMPtr<nsPIDOMWindowOuter> outerWindow = GetOuterWindow();
   4492    fm->WindowShown(outerWindow, oldNeedsFocus);
   4493  }
   4494 }
   4495 
   4496 void nsGlobalWindowInner::PageHidden(bool aIsEnteringBFCacheInParent) {
   4497  // the window is being hidden, so tell the focus manager that the frame is
   4498  // no longer valid. Use the persisted field to determine if the document
   4499  // is being destroyed.
   4500 
   4501  if (RefPtr<nsFocusManager> fm = nsFocusManager::GetFocusManager()) {
   4502    nsCOMPtr<nsPIDOMWindowOuter> outerWindow = GetOuterWindow();
   4503    fm->WindowHidden(outerWindow, nsFocusManager::GenerateFocusActionId(),
   4504                     aIsEnteringBFCacheInParent);
   4505  }
   4506 
   4507  mNeedsFocus = true;
   4508 }
   4509 
   4510 class HashchangeCallback : public Runnable {
   4511 public:
   4512  HashchangeCallback(const nsAString& aOldURL, const nsAString& aNewURL,
   4513                     nsGlobalWindowInner* aWindow)
   4514      : mozilla::Runnable("HashchangeCallback"), mWindow(aWindow) {
   4515    MOZ_ASSERT(mWindow);
   4516    mOldURL.Assign(aOldURL);
   4517    mNewURL.Assign(aNewURL);
   4518  }
   4519 
   4520  NS_IMETHOD Run() override {
   4521    MOZ_ASSERT(NS_IsMainThread(), "Should be called on the main thread.");
   4522    return mWindow->FireHashchange(mOldURL, mNewURL);
   4523  }
   4524 
   4525 private:
   4526  nsString mOldURL;
   4527  nsString mNewURL;
   4528  RefPtr<nsGlobalWindowInner> mWindow;
   4529 };
   4530 
   4531 nsresult nsGlobalWindowInner::DispatchAsyncHashchange(nsIURI* aOldURI,
   4532                                                      nsIURI* aNewURI) {
   4533  // Make sure that aOldURI and aNewURI are identical up to the '#', and that
   4534  // their hashes are different.
   4535  bool equal = false;
   4536  NS_ENSURE_STATE(NS_SUCCEEDED(aOldURI->EqualsExceptRef(aNewURI, &equal)) &&
   4537                  equal);
   4538  nsAutoCString oldHash, newHash;
   4539  bool oldHasHash, newHasHash;
   4540  NS_ENSURE_STATE(NS_SUCCEEDED(aOldURI->GetRef(oldHash)) &&
   4541                  NS_SUCCEEDED(aNewURI->GetRef(newHash)) &&
   4542                  NS_SUCCEEDED(aOldURI->GetHasRef(&oldHasHash)) &&
   4543                  NS_SUCCEEDED(aNewURI->GetHasRef(&newHasHash)) &&
   4544                  (oldHasHash != newHasHash || !oldHash.Equals(newHash)));
   4545 
   4546  nsAutoCString oldSpec, newSpec;
   4547  nsresult rv = aOldURI->GetSpec(oldSpec);
   4548  NS_ENSURE_SUCCESS(rv, rv);
   4549  rv = aNewURI->GetSpec(newSpec);
   4550  NS_ENSURE_SUCCESS(rv, rv);
   4551 
   4552  NS_ConvertUTF8toUTF16 oldWideSpec(oldSpec);
   4553  NS_ConvertUTF8toUTF16 newWideSpec(newSpec);
   4554 
   4555  nsCOMPtr<nsIRunnable> callback =
   4556      new HashchangeCallback(oldWideSpec, newWideSpec, this);
   4557  return Dispatch(callback.forget());
   4558 }
   4559 
   4560 nsresult nsGlobalWindowInner::FireHashchange(const nsAString& aOldURL,
   4561                                             const nsAString& aNewURL) {
   4562  // Don't do anything if the window is frozen.
   4563  if (IsFrozen()) {
   4564    return NS_OK;
   4565  }
   4566 
   4567  // Get a presentation shell for use in creating the hashchange event.
   4568  NS_ENSURE_STATE(IsCurrentInnerWindow());
   4569 
   4570  HashChangeEventInit init;
   4571  init.mNewURL = aNewURL;
   4572  init.mOldURL = aOldURL;
   4573 
   4574  RefPtr<HashChangeEvent> event =
   4575      HashChangeEvent::Constructor(this, u"hashchange"_ns, init);
   4576 
   4577  event->SetTrusted(true);
   4578 
   4579  ErrorResult rv;
   4580  DispatchEvent(*event, rv);
   4581  return rv.StealNSResult();
   4582 }
   4583 
   4584 nsresult nsGlobalWindowInner::DispatchSyncPopState() {
   4585  NS_ASSERTION(nsContentUtils::IsSafeToRunScript(),
   4586               "Must be safe to run script here.");
   4587 
   4588  // Bail if the window is frozen.
   4589  if (IsFrozen()) {
   4590    return NS_OK;
   4591  }
   4592 
   4593  AutoJSAPI jsapi;
   4594  bool result = jsapi.Init(this);
   4595  NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
   4596 
   4597  JSContext* cx = jsapi.cx();
   4598 
   4599  // Get the document's pending state object -- it contains the data we're
   4600  // going to send along with the popstate event.  The object is serialized
   4601  // using structured clone.
   4602  JS::Rooted<JS::Value> stateJSValue(cx);
   4603  nsresult rv = mDoc->GetStateObject(&stateJSValue);
   4604  NS_ENSURE_SUCCESS(rv, rv);
   4605 
   4606  if (!JS_WrapValue(cx, &stateJSValue)) {
   4607    return NS_ERROR_OUT_OF_MEMORY;
   4608  }
   4609 
   4610  RootedDictionary<PopStateEventInit> init(cx);
   4611  init.mState = stateJSValue;
   4612 
   4613  RefPtr<PopStateEvent> event =
   4614      PopStateEvent::Constructor(this, u"popstate"_ns, init);
   4615  event->SetTrusted(true);
   4616  event->SetTarget(this);
   4617 
   4618  ErrorResult err;
   4619  DispatchEvent(*event, err);
   4620  return err.StealNSResult();
   4621 }
   4622 
   4623 already_AddRefed<nsDOMCSSDeclaration> nsGlobalWindowInner::GetComputedStyle(
   4624    Element& aElt, const nsAString& aPseudoElt, ErrorResult& aError) {
   4625  return GetComputedStyleHelper(aElt, aPseudoElt, false, aError);
   4626 }
   4627 
   4628 already_AddRefed<nsDOMCSSDeclaration>
   4629 nsGlobalWindowInner::GetDefaultComputedStyle(Element& aElt,
   4630                                             const nsAString& aPseudoElt,
   4631                                             ErrorResult& aError) {
   4632  return GetComputedStyleHelper(aElt, aPseudoElt, true, aError);
   4633 }
   4634 
   4635 already_AddRefed<nsDOMCSSDeclaration>
   4636 nsGlobalWindowInner::GetComputedStyleHelper(Element& aElt,
   4637                                            const nsAString& aPseudoElt,
   4638                                            bool aDefaultStylesOnly,
   4639                                            ErrorResult& aError) {
   4640  FORWARD_TO_OUTER_OR_THROW(GetComputedStyleHelperOuter,
   4641                            (aElt, aPseudoElt, aDefaultStylesOnly, aError),
   4642                            aError, nullptr);
   4643 }
   4644 
   4645 void nsGlobalWindowInner::MaybeNotifyStorageKeyUsed() {
   4646  // Only notify once per window lifetime.
   4647  if (hasNotifiedStorageKeyUsed) {
   4648    return;
   4649  }
   4650  nsresult rv =
   4651      BounceTrackingStorageObserver::OnInitialStorageAccess(GetWindowContext());
   4652  if (NS_WARN_IF(NS_FAILED(rv))) {
   4653    return;
   4654  }
   4655  hasNotifiedStorageKeyUsed = true;
   4656 }
   4657 
   4658 Storage* nsGlobalWindowInner::GetSessionStorage(ErrorResult& aError) {
   4659  nsIPrincipal* principal = GetPrincipal();
   4660  nsIPrincipal* storagePrincipal;
   4661  if (StaticPrefs::
   4662          privacy_partition_always_partition_third_party_non_cookie_storage_exempt_sessionstorage()) {
   4663    storagePrincipal = GetEffectiveCookiePrincipal();
   4664  } else {
   4665    storagePrincipal = GetEffectiveStoragePrincipal();
   4666  }
   4667  BrowsingContext* browsingContext = GetBrowsingContext();
   4668 
   4669  if (!principal || !storagePrincipal || !browsingContext ||
   4670      !Storage::StoragePrefIsEnabled()) {
   4671    return nullptr;
   4672  }
   4673 
   4674  if (mSessionStorage) {
   4675    MOZ_LOG(gDOMLeakPRLogInner, LogLevel::Debug,
   4676            ("nsGlobalWindowInner %p has %p sessionStorage", this,
   4677             mSessionStorage.get()));
   4678    bool canAccess =
   4679        principal->Subsumes(mSessionStorage->Principal()) &&
   4680        storagePrincipal->Subsumes(mSessionStorage->StoragePrincipal());
   4681    if (!canAccess) {
   4682      mSessionStorage = nullptr;
   4683    }
   4684  }
   4685 
   4686  if (!mSessionStorage) {
   4687    nsString documentURI;
   4688    if (mDoc) {
   4689      aError = mDoc->GetDocumentURI(documentURI);
   4690      if (NS_WARN_IF(aError.Failed())) {
   4691        return nullptr;
   4692      }
   4693    }
   4694 
   4695    if (!mDoc) {
   4696      aError.Throw(NS_ERROR_FAILURE);
   4697      return nullptr;
   4698    }
   4699 
   4700    // If the document's sandboxed origin flag is set, then accessing
   4701    // sessionStorage is prohibited.
   4702    if (mDoc->GetSandboxFlags() & SANDBOXED_ORIGIN) {
   4703      aError.ThrowSecurityError(
   4704          "Forbidden in a sandboxed document without the 'allow-same-origin' "
   4705          "flag.");
   4706      return nullptr;
   4707    }
   4708 
   4709    uint32_t rejectedReason = 0;
   4710    StorageAccess access = StorageAllowedForWindow(this, &rejectedReason);
   4711 
   4712    // SessionStorage is an ephemeral per-tab per-origin storage that only lives
   4713    // as long as the tab is open, although it may survive browser restarts
   4714    // thanks to the session store. So we interpret storage access differently
   4715    // than we would for persistent per-origin storage like LocalStorage and so
   4716    // it may be okay to provide SessionStorage even when we receive a value of
   4717    // eDeny.
   4718    //
   4719    // ContentBlocking::ShouldAllowAccessFor will return false for 3 main
   4720    // reasons.
   4721    //
   4722    // 1. Cookies are entirely blocked due to a per-origin permission
   4723    // (nsICookiePermission::ACCESS_DENY for the top-level principal or this
   4724    // window's principal) or the very broad BEHAVIOR_REJECT. This will return
   4725    // eDeny with a reason of STATE_COOKIES_BLOCKED_BY_PERMISSION or
   4726    // STATE_COOKIES_BLOCKED_ALL.
   4727    //
   4728    // 2. Third-party cookies are limited via BEHAVIOR_REJECT_FOREIGN and
   4729    // BEHAVIOR_LIMIT_FOREIGN and this is a third-party window. This will return
   4730    // eDeny with a reason of STATE_COOKIES_BLOCKED_FOREIGN.
   4731    //
   4732    // 3. Tracking protection (BEHAVIOR_REJECT_TRACKER and
   4733    // BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN) is in effect and
   4734    // IsThirdPartyTrackingResourceWindow() returned true and there wasn't a
   4735    // permission that allows it. This will return ePartitionTrackersOrDeny with
   4736    // a reason of STATE_COOKIES_BLOCKED_TRACKER or
   4737    // STATE_COOKIES_BLOCKED_SOCIALTRACKER.
   4738    //
   4739    // In the 1st case, the user has explicitly indicated that they don't want
   4740    // to allow any storage to the origin or all origins and so we throw an
   4741    // error and deny access to SessionStorage. In the 2nd case, a legacy
   4742    // decision reasoned that there's no harm in providing SessionStorage
   4743    // because the information is not durable and cannot escape the current tab.
   4744    // The rationale is similar for the 3rd case.
   4745    if (access == StorageAccess::eDeny &&
   4746        rejectedReason !=
   4747            nsIWebProgressListener::STATE_COOKIES_BLOCKED_FOREIGN) {
   4748      aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
   4749      return nullptr;
   4750    }
   4751 
   4752    const RefPtr<SessionStorageManager> storageManager =
   4753        browsingContext->GetSessionStorageManager();
   4754    if (!storageManager) {
   4755      aError.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
   4756      return nullptr;
   4757    }
   4758 
   4759    RefPtr<Storage> storage;
   4760    aError = storageManager->CreateStorage(this, principal, storagePrincipal,
   4761                                           documentURI, IsPrivateBrowsing(),
   4762                                           getter_AddRefs(storage));
   4763    if (aError.Failed()) {
   4764      return nullptr;
   4765    }
   4766 
   4767    mSessionStorage = storage;
   4768    MOZ_ASSERT(mSessionStorage);
   4769 
   4770    MOZ_LOG(gDOMLeakPRLogInner, LogLevel::Debug,
   4771            ("nsGlobalWindowInner %p tried to get a new sessionStorage %p",
   4772             this, mSessionStorage.get()));
   4773 
   4774    if (!mSessionStorage) {
   4775      aError.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
   4776      return nullptr;
   4777    }
   4778  }
   4779 
   4780  MaybeNotifyStorageKeyUsed();
   4781 
   4782  MOZ_LOG(gDOMLeakPRLogInner, LogLevel::Debug,
   4783          ("nsGlobalWindowInner %p returns %p sessionStorage", this,
   4784           mSessionStorage.get()));
   4785 
   4786  return mSessionStorage;
   4787 }
   4788 
   4789 Storage* nsGlobalWindowInner::GetLocalStorage(ErrorResult& aError) {
   4790  if (!Storage::StoragePrefIsEnabled()) {
   4791    return nullptr;
   4792  }
   4793 
   4794  // If the document's sandboxed origin flag is set, then accessing localStorage
   4795  // is prohibited.
   4796  if (mDoc && mDoc->GetSandboxFlags() & SANDBOXED_ORIGIN) {
   4797    aError.ThrowSecurityError(
   4798        "Forbidden in a sandboxed document without the 'allow-same-origin' "
   4799        "flag.");
   4800    return nullptr;
   4801  }
   4802 
   4803  // LocalStorage needs to be exposed in every context except for sandboxes and
   4804  // NullPrincipals (data: URLs, for instance). But we need to keep data
   4805  // separate in some scenarios: private-browsing and partitioned trackers.
   4806  // In private-browsing, LocalStorage keeps data in memory, and it shares
   4807  // StorageEvents just with other origins in the same private-browsing
   4808  // environment.
   4809  // For Partitioned Trackers, we expose a partitioned LocalStorage, which
   4810  // doesn't share data with other contexts, and it's just in memory.
   4811  // Partitioned localStorage is available only for trackers listed in the
   4812  // privacy.restrict3rdpartystorage.partitionedHosts pref. See
   4813  // nsContentUtils::IsURIInPrefList to know the syntax for the pref value.
   4814  // This is a temporary web-compatibility hack.
   4815 
   4816  StorageAccess access = StorageAllowedForWindow(this);
   4817 
   4818  // We allow partitioned localStorage only to some hosts.
   4819  bool isolated = false;
   4820  if (ShouldPartitionStorage(access)) {
   4821    if (!mDoc) {
   4822      access = StorageAccess::eDeny;
   4823    } else if (!StoragePartitioningEnabled(access, mDoc->CookieJarSettings())) {
   4824      static const char* kPrefName =
   4825          "privacy.restrict3rdpartystorage.partitionedHosts";
   4826 
   4827      bool isInList = false;
   4828      mDoc->NodePrincipal()->IsURIInPrefList(kPrefName, &isInList);
   4829      if (!isInList) {
   4830        access = StorageAccess::eDeny;
   4831      } else {
   4832        isolated = true;
   4833      }
   4834    }
   4835  }
   4836 
   4837  if (access == StorageAccess::eDeny) {
   4838    aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
   4839    return nullptr;
   4840  }
   4841 
   4842  nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
   4843  if (mDoc) {
   4844    cookieJarSettings = mDoc->CookieJarSettings();
   4845  } else {
   4846    cookieJarSettings = net::CookieJarSettings::GetBlockingAll(
   4847        ShouldResistFingerprinting(RFPTarget::IsAlwaysEnabledForPrecompute));
   4848  }
   4849 
   4850  // Note that this behavior is observable: if we grant storage permission to a
   4851  // tracker, we pass from the partitioned LocalStorage (or a partitioned cookie
   4852  // jar) to the 'normal' one. The previous data is lost and the 2
   4853  // window.localStorage objects, before and after the permission granted, will
   4854  // be different.
   4855  if (mLocalStorage) {
   4856    if ((mLocalStorage->Type() == (isolated ? Storage::ePartitionedLocalStorage
   4857                                            : Storage::eLocalStorage)) &&
   4858        (mLocalStorage->StoragePrincipal() == GetEffectiveStoragePrincipal())) {
   4859      return mLocalStorage;
   4860    }
   4861 
   4862    // storage needs change
   4863    mLocalStorage = nullptr;
   4864  }
   4865 
   4866  MOZ_ASSERT(!mLocalStorage);
   4867 
   4868  if (!isolated) {
   4869    RefPtr<Storage> storage;
   4870 
   4871    if (NextGenLocalStorageEnabled()) {
   4872      aError = LSObject::CreateForWindow(this, getter_AddRefs(storage));
   4873    } else {
   4874      nsresult rv;
   4875      nsCOMPtr<nsIDOMStorageManager> storageManager =
   4876          do_GetService("@mozilla.org/dom/localStorage-manager;1", &rv);
   4877      if (NS_FAILED(rv)) {
   4878        aError.Throw(rv);
   4879        return nullptr;
   4880      }
   4881 
   4882      nsString documentURI;
   4883      if (mDoc) {
   4884        aError = mDoc->GetDocumentURI(documentURI);
   4885        if (NS_WARN_IF(aError.Failed())) {
   4886          return nullptr;
   4887        }
   4888      }
   4889 
   4890      nsIPrincipal* principal = GetPrincipal();
   4891      if (!principal) {
   4892        aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
   4893        return nullptr;
   4894      }
   4895 
   4896      nsIPrincipal* storagePrincipal = GetEffectiveStoragePrincipal();
   4897      if (!storagePrincipal) {
   4898        aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
   4899        return nullptr;
   4900      }
   4901 
   4902      aError = storageManager->CreateStorage(this, principal, storagePrincipal,
   4903                                             documentURI, IsPrivateBrowsing(),
   4904                                             getter_AddRefs(storage));
   4905    }
   4906 
   4907    if (aError.Failed()) {
   4908      return nullptr;
   4909    }
   4910 
   4911    mLocalStorage = storage;
   4912  } else {
   4913    nsresult rv;
   4914    nsCOMPtr<nsIDOMSessionStorageManager> storageManager =
   4915        do_GetService("@mozilla.org/dom/sessionStorage-manager;1", &rv);
   4916    if (NS_FAILED(rv)) {
   4917      aError.Throw(rv);
   4918      return nullptr;
   4919    }
   4920 
   4921    nsIPrincipal* principal = GetPrincipal();
   4922    if (!principal) {
   4923      aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
   4924      return nullptr;
   4925    }
   4926 
   4927    nsIPrincipal* storagePrincipal = GetEffectiveStoragePrincipal();
   4928    if (!storagePrincipal) {
   4929      aError.Throw(NS_ERROR_DOM_SECURITY_ERR);
   4930      return nullptr;
   4931    }
   4932 
   4933    RefPtr<SessionStorageCache> cache;
   4934    if (isolated) {
   4935      cache = new SessionStorageCache();
   4936    } else {
   4937      // This will clone the session storage if it exists.
   4938      rv = storageManager->GetSessionStorageCache(principal, storagePrincipal,
   4939                                                  &cache);
   4940      if (NS_FAILED(rv)) {
   4941        aError.Throw(rv);
   4942        return nullptr;
   4943      }
   4944    }
   4945 
   4946    mLocalStorage =
   4947        new PartitionedLocalStorage(this, principal, storagePrincipal, cache);
   4948  }
   4949 
   4950  MaybeNotifyStorageKeyUsed();
   4951 
   4952  MOZ_ASSERT(mLocalStorage);
   4953  MOZ_ASSERT(
   4954      mLocalStorage->Type() ==
   4955      (isolated ? Storage::ePartitionedLocalStorage : Storage::eLocalStorage));
   4956  return mLocalStorage;
   4957 }
   4958 
   4959 IDBFactory* nsGlobalWindowInner::GetIndexedDB(JSContext* aCx,
   4960                                              ErrorResult& aError) {
   4961  if (!mIndexedDB) {
   4962    // This may keep mIndexedDB null without setting an error.
   4963    auto res = IDBFactory::CreateForWindow(this);
   4964    if (res.isErr()) {
   4965      aError = res.unwrapErr();
   4966    } else {
   4967      mIndexedDB = res.unwrap();
   4968    }
   4969  }
   4970 
   4971  MaybeNotifyStorageKeyUsed();
   4972 
   4973  return mIndexedDB;
   4974 }
   4975 
   4976 //*****************************************************************************
   4977 // nsGlobalWindowInner::nsIInterfaceRequestor
   4978 //*****************************************************************************
   4979 
   4980 NS_IMETHODIMP
   4981 nsGlobalWindowInner::GetInterface(const nsIID& aIID, void** aSink) {
   4982  nsGlobalWindowOuter* outer = GetOuterWindowInternal();
   4983  NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
   4984 
   4985  nsresult rv = outer->GetInterfaceInternal(aIID, aSink);
   4986  if (rv == NS_ERROR_NO_INTERFACE) {
   4987    return QueryInterface(aIID, aSink);
   4988  }
   4989  return rv;
   4990 }
   4991 
   4992 void nsGlobalWindowInner::GetInterface(JSContext* aCx,
   4993                                       JS::Handle<JS::Value> aIID,
   4994                                       JS::MutableHandle<JS::Value> aRetval,
   4995                                       ErrorResult& aError) {
   4996  dom::GetInterface(aCx, this, aIID, aRetval, aError);
   4997 }
   4998 
   4999 already_AddRefed<CacheStorage> nsGlobalWindowInner::GetCaches(
   5000    ErrorResult& aRv) {
   5001  if (!mCacheStorage) {
   5002    bool forceTrustedOrigin =
   5003        GetBrowsingContext() &&
   5004        GetBrowsingContext()->Top()->GetServiceWorkersTestingEnabled();
   5005    mCacheStorage = CacheStorage::CreateOnMainThread(
   5006        cache::DEFAULT_NAMESPACE, this, GetEffectiveStoragePrincipal(),
   5007        forceTrustedOrigin, aRv);
   5008  }
   5009 
   5010  RefPtr<CacheStorage> ref = mCacheStorage;
   5011  return ref.forget();
   5012 }
   5013 
   5014 void nsGlobalWindowInner::FireOfflineStatusEventIfChanged() {
   5015  if (!IsCurrentInnerWindow()) return;
   5016 
   5017  bool isOffline =
   5018      NS_IsOffline() ||
   5019      (GetBrowsingContext() && GetBrowsingContext()->Top()->GetForceOffline());
   5020 
   5021  // Don't fire an event if the status hasn't changed
   5022  if (mWasOffline == isOffline) {
   5023    return;
   5024  }
   5025 
   5026  if (ShouldResistFingerprinting(RFPTarget::NetworkConnection)) {
   5027    // We always report online=true when resistFingerprinting is enabled.
   5028    return;
   5029  }
   5030 
   5031  mWasOffline = !mWasOffline;
   5032 
   5033  nsAutoString name;
   5034  if (mWasOffline) {
   5035    name.AssignLiteral("offline");
   5036  } else {
   5037    name.AssignLiteral("online");
   5038  }
   5039  nsContentUtils::DispatchTrustedEvent(mDoc, this, name, CanBubble::eNo,
   5040                                       Cancelable::eNo);
   5041 }
   5042 
   5043 nsGlobalWindowInner::SlowScriptResponse
   5044 nsGlobalWindowInner::ShowSlowScriptDialog(JSContext* aCx,
   5045                                          const nsString& aAddonId,
   5046                                          const double aDuration) {
   5047  nsresult rv;
   5048 
   5049  if (Preferences::GetBool("dom.always_stop_slow_scripts")) {
   5050    return KillSlowScript;
   5051  }
   5052 
   5053  // If it isn't safe to run script, then it isn't safe to bring up the prompt
   5054  // (since that spins the event loop). In that (rare) case, we just kill the
   5055  // script and report a warning.
   5056  if (!nsContentUtils::IsSafeToRunScript()) {
   5057    JS::WarnASCII(aCx, "A long running script was terminated");
   5058    return KillSlowScript;
   5059  }
   5060 
   5061  // If our document is not active, just kill the script: we've been unloaded
   5062  if (!HasActiveDocument()) {
   5063    return KillSlowScript;
   5064  }
   5065 
   5066  // Check if we should offer the option to debug
   5067  JS::AutoFilename filename;
   5068  uint32_t lineno;
   5069  // Computing the line number can be very expensive (see bug 1330231 for
   5070  // example), and we don't use the line number anywhere except than in the
   5071  // parent process, so we avoid computing it elsewhere.  This gives us most of
   5072  // the wins we are interested in, since the source of the slowness here is
   5073  // minified scripts which is more common in Web content that is loaded in the
   5074  // content process.
   5075  uint32_t* linenop = XRE_IsParentProcess() ? &lineno : nullptr;
   5076  bool hasFrame = JS::DescribeScriptedCaller(&filename, aCx, linenop);
   5077 
   5078  // Record the slow script event if we haven't done so already for this inner
   5079  // window (which represents a particular page to the user).
   5080  if (!mHasHadSlowScript) {
   5081    glean::dom::slow_script_page_count.Add(1);
   5082  }
   5083  mHasHadSlowScript = true;
   5084 
   5085  // Override the cursor to something that we're sure the user can see.
   5086  SetCursor("auto"_ns, IgnoreErrors());
   5087 
   5088  if (XRE_IsContentProcess() && ProcessHangMonitor::Get()) {
   5089    ProcessHangMonitor::SlowScriptAction action;
   5090    RefPtr<ProcessHangMonitor> monitor = ProcessHangMonitor::Get();
   5091    nsIDocShell* docShell = GetDocShell();
   5092    nsCOMPtr<nsIBrowserChild> child =
   5093        docShell ? docShell->GetBrowserChild() : nullptr;
   5094    action =
   5095        monitor->NotifySlowScript(child, filename.get(), aAddonId, aDuration);
   5096    if (action == ProcessHangMonitor::Terminate) {
   5097      return KillSlowScript;
   5098    }
   5099 
   5100    if (action == ProcessHangMonitor::StartDebugger) {
   5101      // Spin a nested event loop so that the debugger in the parent can fetch
   5102      // any information it needs. Once the debugger has started, return to the
   5103      // script.
   5104      RefPtr<nsGlobalWindowOuter> outer = GetOuterWindowInternal();
   5105      outer->EnterModalState();
   5106      SpinEventLoopUntil("nsGlobalWindowInner::ShowSlowScriptDialog"_ns, [&]() {
   5107        return monitor->IsDebuggerStartupComplete() ||
   5108               AppShutdown::IsShutdownImpending();
   5109      });
   5110      outer->LeaveModalState();
   5111      return (AppShutdown::IsShutdownImpending()) ? KillSlowScript
   5112                                                  : ContinueSlowScript;
   5113    }
   5114 
   5115    return ContinueSlowScriptAndKeepNotifying;
   5116  }
   5117 
   5118  // Reached only on non-e10s - once per slow script dialog.
   5119  // On e10s - we probe once at ProcessHangsMonitor.sys.mjs
   5120  glean::dom::slow_script_notice_count.Add(1);
   5121 
   5122  // Get the nsIPrompt interface from the docshell
   5123  nsCOMPtr<nsIDocShell> ds = GetDocShell();
   5124  NS_ENSURE_TRUE(ds, KillSlowScript);
   5125  nsCOMPtr<nsIPrompt> prompt = do_GetInterface(ds);
   5126  NS_ENSURE_TRUE(prompt, KillSlowScript);
   5127 
   5128  // Prioritize the SlowScriptDebug interface over JSD1.
   5129  nsCOMPtr<nsISlowScriptDebugCallback> debugCallback;
   5130 
   5131  if (hasFrame) {
   5132    const char* debugCID = "@mozilla.org/dom/slow-script-debug;1";
   5133    nsCOMPtr<nsISlowScriptDebug> debugService = do_GetService(debugCID, &rv);
   5134    if (NS_SUCCEEDED(rv)) {
   5135      debugService->GetActivationHandler(getter_AddRefs(debugCallback));
   5136    }
   5137  }
   5138 
   5139  bool failed = false;
   5140  auto getString = [&](const char* name,
   5141                       nsContentUtils::PropertiesFile propFile =
   5142                           nsContentUtils::eDOM_PROPERTIES) {
   5143    nsAutoString result;
   5144    nsresult rv = nsContentUtils::GetLocalizedString(propFile, name, result);
   5145 
   5146    // GetStringFromName can return NS_OK and still give nullptr string
   5147    failed = failed || NS_FAILED(rv) || result.IsEmpty();
   5148    return result;
   5149  };
   5150 
   5151  bool isAddonScript = !aAddonId.IsEmpty();
   5152  bool showDebugButton = debugCallback && !isAddonScript;
   5153 
   5154  // Get localizable strings
   5155 
   5156  nsAutoString title, checkboxMsg, debugButton, msg;
   5157  if (isAddonScript) {
   5158    title = getString("KillAddonScriptTitle");
   5159    checkboxMsg = getString("KillAddonScriptGlobalMessage");
   5160 
   5161    auto appName =
   5162        getString("brandShortName", nsContentUtils::eBRAND_PROPERTIES);
   5163 
   5164    nsCOMPtr<nsIAddonPolicyService> aps =
   5165        do_GetService("@mozilla.org/addons/policy-service;1");
   5166    nsString addonName;
   5167    if (!aps || NS_FAILED(aps->GetExtensionName(aAddonId, addonName))) {
   5168      addonName = aAddonId;
   5169    }
   5170 
   5171    rv = nsContentUtils::FormatLocalizedString(
   5172        msg, nsContentUtils::eDOM_PROPERTIES, "KillAddonScriptMessage",
   5173        addonName, appName);
   5174 
   5175    failed = failed || NS_FAILED(rv);
   5176  } else {
   5177    title = getString("KillScriptTitle");
   5178    checkboxMsg = getString("DontAskAgain");
   5179 
   5180    if (showDebugButton) {
   5181      debugButton = getString("DebugScriptButton");
   5182      msg = getString("KillScriptWithDebugMessage");
   5183    } else {
   5184      msg = getString("KillScriptMessage");
   5185    }
   5186  }
   5187 
   5188  auto stopButton = getString("StopScriptButton");
   5189  auto waitButton = getString("WaitForScriptButton");
   5190 
   5191  if (failed) {
   5192    NS_ERROR("Failed to get localized strings.");
   5193    return ContinueSlowScript;
   5194  }
   5195 
   5196  // Append file and line number information, if available
   5197  if (filename.get()) {
   5198    nsAutoString scriptLocation;
   5199    // We want to drop the middle part of too-long locations.  We'll
   5200    // define "too-long" as longer than 60 UTF-16 code units.  Just
   5201    // have to be a bit careful about unpaired surrogates.
   5202    NS_ConvertUTF8toUTF16 filenameUTF16(filename.get());
   5203    if (filenameUTF16.Length() > 60) {
   5204      // XXXbz Do we need to insert any bidi overrides here?
   5205      size_t cutStart = 30;
   5206      size_t cutLength = filenameUTF16.Length() - 60;
   5207      MOZ_ASSERT(cutLength > 0);
   5208      if (NS_IS_LOW_SURROGATE(filenameUTF16[cutStart])) {
   5209        // Don't truncate before the low surrogate, in case it's preceded by a
   5210        // high surrogate and forms a single Unicode character.  Instead, just
   5211        // include the low surrogate.
   5212        ++cutStart;
   5213        --cutLength;
   5214      }
   5215      if (NS_IS_LOW_SURROGATE(filenameUTF16[cutStart + cutLength])) {
   5216        // Likewise, don't drop a trailing low surrogate here.  We want to
   5217        // increase cutLength, since it might be 0 already so we can't very well
   5218        // decrease it.
   5219        ++cutLength;
   5220      }
   5221 
   5222      // Insert U+2026 HORIZONTAL ELLIPSIS
   5223      filenameUTF16.ReplaceLiteral(cutStart, cutLength, u"\x2026");
   5224    }
   5225    rv = nsContentUtils::FormatLocalizedString(
   5226        scriptLocation, nsContentUtils::eDOM_PROPERTIES, "KillScriptLocation",
   5227        filenameUTF16);
   5228 
   5229    if (NS_SUCCEEDED(rv)) {
   5230      msg.AppendLiteral("\n\n");
   5231      msg.Append(scriptLocation);
   5232      msg.Append(':');
   5233      msg.AppendInt(lineno);
   5234    }
   5235  }
   5236 
   5237  uint32_t buttonFlags = nsIPrompt::BUTTON_POS_1_DEFAULT +
   5238                         (nsIPrompt::BUTTON_TITLE_IS_STRING *
   5239                          (nsIPrompt::BUTTON_POS_0 + nsIPrompt::BUTTON_POS_1));
   5240 
   5241  // Add a third button if necessary.
   5242  if (showDebugButton)
   5243    buttonFlags += nsIPrompt::BUTTON_TITLE_IS_STRING * nsIPrompt::BUTTON_POS_2;
   5244 
   5245  bool checkboxValue = false;
   5246  int32_t buttonPressed = 0;  // In case the user exits dialog by clicking X.
   5247  {
   5248    // Null out the operation callback while we're re-entering JS here.
   5249    AutoDisableJSInterruptCallback disabler(aCx);
   5250 
   5251    // Open the dialog.
   5252    rv = prompt->ConfirmEx(
   5253        title.get(), msg.get(), buttonFlags, waitButton.get(), stopButton.get(),
   5254        debugButton.get(), checkboxMsg.get(), &checkboxValue, &buttonPressed);
   5255  }
   5256 
   5257  if (buttonPressed == 0) {
   5258    if (checkboxValue && !isAddonScript && NS_SUCCEEDED(rv))
   5259      return AlwaysContinueSlowScript;
   5260    return ContinueSlowScript;
   5261  }
   5262 
   5263  if (buttonPressed == 2) {
   5264    MOZ_RELEASE_ASSERT(debugCallback);
   5265 
   5266    rv = debugCallback->HandleSlowScriptDebug(this);
   5267    return NS_SUCCEEDED(rv) ? ContinueSlowScript : KillSlowScript;
   5268  }
   5269 
   5270  JS_ClearPendingException(aCx);
   5271 
   5272  return KillSlowScript;
   5273 }
   5274 
   5275 nsresult nsGlobalWindowInner::Observe(nsISupports* aSubject, const char* aTopic,
   5276                                      const char16_t* aData) {
   5277  if (!nsCRT::strcmp(aTopic, "audio-playback")) {
   5278    if (ToSupports(GetOuterWindow()) != aSubject) {
   5279      return NS_OK;
   5280    }
   5281    AUTO_PROFILER_MARKER_UNTYPED("audio-playback", DOM, {});
   5282 
   5283    nsGlobalWindowOuter* outer =
   5284        nsGlobalWindowOuter::Cast(nsPIDOMWindowOuter::From(GetOuterWindow())
   5285                                      ->GetInProcessScriptableTop());
   5286    nsGlobalWindowInner* topInnerWindow =
   5287        outer ? nsGlobalWindowInner::Cast(outer->GetCurrentInnerWindow())
   5288              : nullptr;
   5289 
   5290    if (topInnerWindow) {
   5291      const bool isPlayingAudio{IsPlayingAudio()};
   5292      topInnerWindow->AudioPlaybackChanged(isPlayingAudio);
   5293      topInnerWindow->CallOnInProcessDescendants(
   5294          &nsGlobalWindowInner::AudioPlaybackChanged, isPlayingAudio);
   5295    }
   5296 
   5297    return NS_OK;
   5298  }
   5299 
   5300  if (!nsCRT::strcmp(aTopic, NS_IOSERVICE_OFFLINE_STATUS_TOPIC)) {
   5301    if (!IsFrozen()) {
   5302      // Fires an offline status event if the offline status has changed
   5303      FireOfflineStatusEventIfChanged();
   5304    }
   5305    return NS_OK;
   5306  }
   5307 
   5308  if (!nsCRT::strcmp(aTopic, MEMORY_PRESSURE_OBSERVER_TOPIC)) {
   5309    if (mPerformance) {
   5310      mPerformance->MemoryPressure();
   5311    }
   5312    RemoveReportRecords();
   5313    return NS_OK;
   5314  }
   5315 
   5316  if (!nsCRT::strcmp(aTopic, PERMISSION_CHANGED_TOPIC)) {
   5317    nsCOMPtr<nsIPermission> perm(do_QueryInterface(aSubject));
   5318    if (!perm) {
   5319      // A null permission indicates that the entire permission list
   5320      // was cleared.
   5321      MOZ_ASSERT(!nsCRT::strcmp(aData, u"cleared"));
   5322      UpdatePermissions();
   5323      return NS_OK;
   5324    }
   5325 
   5326    nsAutoCString type;
   5327    perm->GetType(type);
   5328    if (type == "autoplay-media"_ns) {
   5329      UpdateAutoplayPermission();
   5330    } else if (type == "shortcuts"_ns) {
   5331      UpdateShortcutsPermission();
   5332    } else if (type == "popup"_ns) {
   5333      UpdatePopupPermission();
   5334    }
   5335 
   5336    if (!mDoc) {
   5337      return NS_OK;
   5338    }
   5339 
   5340    RefPtr<PermissionDelegateHandler> permDelegateHandler =
   5341        mDoc->GetPermissionDelegateHandler();
   5342 
   5343    if (permDelegateHandler) {
   5344      permDelegateHandler->UpdateDelegatedPermission(type);
   5345    }
   5346 
   5347    return NS_OK;
   5348  }
   5349 
   5350  if (!nsCRT::strcmp(aTopic, "screen-information-changed")) {
   5351    if (mScreen) {
   5352      if (RefPtr<ScreenOrientation> orientation =
   5353              mScreen->GetOrientationIfExists()) {
   5354        orientation->MaybeChanged();
   5355      }
   5356    }
   5357    if (mHasOrientationChangeListeners) {
   5358      int32_t oldAngle = mOrientationAngle;
   5359      mOrientationAngle = Orientation(CallerType::System);
   5360      if (mOrientationAngle != oldAngle && IsCurrentInnerWindow()) {
   5361        nsCOMPtr<nsPIDOMWindowOuter> outer = GetOuterWindow();
   5362        outer->DispatchCustomEvent(u"orientationchange"_ns);
   5363      }
   5364    }
   5365    return NS_OK;
   5366  }
   5367 
   5368  if (!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
   5369    MOZ_ASSERT(!NS_strcmp(aData, u"intl.accept_languages"));
   5370 
   5371    // The user preferred languages have changed, we need to fire an event on
   5372    // Window object and invalidate the cache for navigator.languages. It is
   5373    // done for every change which can be a waste of cycles but those should be
   5374    // fairly rare.
   5375    // We MUST invalidate navigator.languages before sending the event in the
   5376    // very likely situation where an event handler will try to read its value.
   5377 
   5378    if (mNavigator) {
   5379      Navigator_Binding::ClearCachedLanguageValue(mNavigator);
   5380      Navigator_Binding::ClearCachedLanguagesValue(mNavigator);
   5381    }
   5382 
   5383    // The event has to be dispatched only to the current inner window.
   5384    if (!IsCurrentInnerWindow()) {
   5385      return NS_OK;
   5386    }
   5387 
   5388    RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
   5389    event->InitEvent(u"languagechange"_ns, false, false);
   5390    event->SetTrusted(true);
   5391 
   5392    ErrorResult rv;
   5393    DispatchEvent(*event, rv);
   5394    return rv.StealNSResult();
   5395  }
   5396 
   5397  NS_WARNING(nsPrintfCString("unrecognized topic %s", aTopic).get());
   5398  return NS_ERROR_FAILURE;
   5399 }
   5400 
   5401 void nsGlobalWindowInner::ObserveStorageNotification(
   5402    StorageEvent* aEvent, const char16_t* aStorageType, bool aPrivateBrowsing) {
   5403  MOZ_ASSERT(aEvent);
   5404 
   5405  // The private browsing check must be done here again because this window
   5406  // could have changed its state before the notification check and now. This
   5407  // happens in case this window did have a docShell at that time.
   5408  if (aPrivateBrowsing != IsPrivateBrowsing()) {
   5409    return;
   5410  }
   5411 
   5412  // LocalStorage can only exist on an inner window, and we don't want to
   5413  // generate events on frozen or otherwise-navigated-away from windows.
   5414  // (Actually, this code used to try and buffer events for frozen windows,
   5415  // but it never worked, so we've removed it.  See bug 1285898.)
   5416  if (!IsCurrentInnerWindow() || IsFrozen()) {
   5417    return;
   5418  }
   5419 
   5420  nsIPrincipal* principal = GetPrincipal();
   5421  if (!principal) {
   5422    return;
   5423  }
   5424 
   5425  bool fireMozStorageChanged = false;
   5426  nsAutoString eventType;
   5427  eventType.AssignLiteral("storage");
   5428 
   5429  if (!NS_strcmp(aStorageType, u"sessionStorage")) {
   5430    RefPtr<Storage> changingStorage = aEvent->GetStorageArea();
   5431    MOZ_ASSERT(changingStorage);
   5432 
   5433    bool check = false;
   5434 
   5435    if (const RefPtr<SessionStorageManager> storageManager =
   5436            GetBrowsingContext()->GetSessionStorageManager()) {
   5437      nsresult rv = storageManager->CheckStorage(GetEffectiveStoragePrincipal(),
   5438                                                 changingStorage, &check);
   5439      if (NS_FAILED(rv)) {
   5440        return;
   5441      }
   5442    }
   5443 
   5444    if (!check) {
   5445      // This storage event is not coming from our storage or is coming
   5446      // from a different docshell, i.e. it is a clone, ignore this event.
   5447      return;
   5448    }
   5449 
   5450    MOZ_LOG(
   5451        gDOMLeakPRLogInner, LogLevel::Debug,
   5452        ("nsGlobalWindowInner %p with sessionStorage %p passing event from %p",
   5453         this, mSessionStorage.get(), changingStorage.get()));
   5454 
   5455    fireMozStorageChanged = mSessionStorage == changingStorage;
   5456    if (fireMozStorageChanged) {
   5457      eventType.AssignLiteral("MozSessionStorageChanged");
   5458    }
   5459  }
   5460 
   5461  else {
   5462    MOZ_ASSERT(!NS_strcmp(aStorageType, u"localStorage"));
   5463 
   5464    nsIPrincipal* storagePrincipal = GetEffectiveStoragePrincipal();
   5465    if (!storagePrincipal) {
   5466      return;
   5467    }
   5468 
   5469    MOZ_DIAGNOSTIC_ASSERT(StorageUtils::PrincipalsEqual(aEvent->GetPrincipal(),
   5470                                                        storagePrincipal));
   5471 
   5472    fireMozStorageChanged =
   5473        mLocalStorage && mLocalStorage == aEvent->GetStorageArea();
   5474 
   5475    if (fireMozStorageChanged) {
   5476      eventType.AssignLiteral("MozLocalStorageChanged");
   5477    }
   5478  }
   5479 
   5480  // Clone the storage event included in the observer notification. We want
   5481  // to dispatch clones rather than the original event.
   5482  IgnoredErrorResult error;
   5483  RefPtr<StorageEvent> clonedEvent =
   5484      CloneStorageEvent(eventType, aEvent, error);
   5485  if (error.Failed() || !clonedEvent) {
   5486    return;
   5487  }
   5488 
   5489  clonedEvent->SetTrusted(true);
   5490 
   5491  if (fireMozStorageChanged) {
   5492    WidgetEvent* internalEvent = clonedEvent->WidgetEventPtr();
   5493    internalEvent->mFlags.mOnlyChromeDispatch = true;
   5494  }
   5495 
   5496  DispatchEvent(*clonedEvent);
   5497 }
   5498 
   5499 already_AddRefed<StorageEvent> nsGlobalWindowInner::CloneStorageEvent(
   5500    const nsAString& aType, const RefPtr<StorageEvent>& aEvent,
   5501    ErrorResult& aRv) {
   5502  StorageEventInit dict;
   5503 
   5504  dict.mBubbles = aEvent->Bubbles();
   5505  dict.mCancelable = aEvent->Cancelable();
   5506  aEvent->GetKey(dict.mKey);
   5507  aEvent->GetOldValue(dict.mOldValue);
   5508  aEvent->GetNewValue(dict.mNewValue);
   5509  aEvent->GetUrl(dict.mUrl);
   5510 
   5511  RefPtr<Storage> storageArea = aEvent->GetStorageArea();
   5512 
   5513  RefPtr<Storage> storage;
   5514 
   5515  // If null, this is a localStorage event received by IPC.
   5516  if (!storageArea) {
   5517    storage = GetLocalStorage(aRv);
   5518    if (!NextGenLocalStorageEnabled()) {
   5519      if (aRv.Failed() || !storage) {
   5520        return nullptr;
   5521      }
   5522 
   5523      if (storage->Type() == Storage::eLocalStorage) {
   5524        RefPtr<LocalStorage> localStorage =
   5525            static_cast<LocalStorage*>(storage.get());
   5526 
   5527        // We must apply the current change to the 'local' localStorage.
   5528        localStorage->ApplyEvent(aEvent);
   5529      }
   5530    }
   5531  } else if (storageArea->Type() == Storage::eSessionStorage) {
   5532    storage = GetSessionStorage(aRv);
   5533  } else {
   5534    MOZ_ASSERT(storageArea->Type() == Storage::eLocalStorage);
   5535    storage = GetLocalStorage(aRv);
   5536  }
   5537 
   5538  if (aRv.Failed() || !storage) {
   5539    return nullptr;
   5540  }
   5541 
   5542  if (storage->Type() == Storage::ePartitionedLocalStorage) {
   5543    // This error message is not exposed.
   5544    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
   5545    return nullptr;
   5546  }
   5547 
   5548  MOZ_ASSERT(storage);
   5549  MOZ_ASSERT_IF(storageArea, storage->IsForkOf(storageArea));
   5550 
   5551  dict.mStorageArea = storage;
   5552 
   5553  RefPtr<StorageEvent> event = StorageEvent::Constructor(this, aType, dict);
   5554  return event.forget();
   5555 }
   5556 
   5557 void nsGlobalWindowInner::Suspend(bool aIncludeSubWindows) {
   5558  MOZ_ASSERT(NS_IsMainThread());
   5559 
   5560  // We can only safely suspend windows that are the current inner window.  If
   5561  // its not the current inner, then we are in one of two different cases.
   5562  // Either we are in the bfcache or we are doomed window that is going away.
   5563  // When a window becomes inactive we purposely avoid placing already suspended
   5564  // windows into the bfcache.  It only expects windows suspended due to the
   5565  // Freeze() method which occurs while the window is still the current inner.
   5566  // So we must not call Suspend() on bfcache windows at this point or this
   5567  // invariant will be broken.  If the window is doomed there is no point in
   5568  // suspending it since it will soon be gone.
   5569  if (!IsCurrentInnerWindow()) {
   5570    return;
   5571  }
   5572 
   5573  // All in-process descendants are also suspended.  This ensure mSuspendDepth
   5574  // is set properly and the timers are properly canceled for each in-process
   5575  // descendant.
   5576  if (aIncludeSubWindows) {
   5577    CallOnInProcessDescendants(&nsGlobalWindowInner::Suspend, false);
   5578  }
   5579 
   5580  mSuspendDepth += 1;
   5581  if (mSuspendDepth != 1) {
   5582    return;
   5583  }
   5584 
   5585  if (mWindowGlobalChild) {
   5586    mWindowGlobalChild->BlockBFCacheFor(BFCacheStatus::SUSPENDED);
   5587  }
   5588 
   5589  nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
   5590  if (ac) {
   5591    for (uint32_t i = 0; i < mEnabledSensors.Length(); i++)
   5592      ac->RemoveWindowListener(mEnabledSensors[i], this);
   5593  }
   5594  DisableGamepadUpdates();
   5595  DisableVRUpdates();
   5596 
   5597  SuspendWorkersForWindow(*this);
   5598 
   5599  for (RefPtr<mozilla::dom::SharedWorker> pinnedWorker :
   5600       mSharedWorkers.ForwardRange()) {
   5601    pinnedWorker->Suspend();
   5602  }
   5603 
   5604  SuspendIdleRequests();
   5605 
   5606  mTimeoutManager->Suspend();
   5607 
   5608  // Suspend all of the AudioContexts for this window
   5609  for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
   5610    mAudioContexts[i]->SuspendFromChrome();
   5611  }
   5612 }
   5613 
   5614 void nsGlobalWindowInner::Resume(bool aIncludeSubWindows) {
   5615  MOZ_ASSERT(NS_IsMainThread());
   5616 
   5617  // We can only safely resume a window if its the current inner window.  If
   5618  // its not the current inner, then we are in one of two different cases.
   5619  // Either we are in the bfcache or we are doomed window that is going away.
   5620  // If a window is suspended when it becomes inactive we purposely do not
   5621  // put it in the bfcache, so Resume should never be needed in that case.
   5622  // If the window is doomed then there is no point in resuming it.
   5623  if (!IsCurrentInnerWindow()) {
   5624    return;
   5625  }
   5626 
   5627  // Resume all in-process descendants.  This restores timers recursively
   5628  // canceled in Suspend() and ensures all in-process descendants have the
   5629  // correct mSuspendDepth.
   5630  if (aIncludeSubWindows) {
   5631    CallOnInProcessDescendants(&nsGlobalWindowInner::Resume, false);
   5632  }
   5633 
   5634  if (mSuspendDepth == 0) {
   5635    // Ignore if the window is not suspended.
   5636    return;
   5637  }
   5638 
   5639  mSuspendDepth -= 1;
   5640 
   5641  if (mSuspendDepth != 0) {
   5642    return;
   5643  }
   5644 
   5645  // We should not be able to resume a frozen window.  It must be Thaw()'d
   5646  // first.
   5647  MOZ_ASSERT(mFreezeDepth == 0);
   5648 
   5649  nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
   5650  if (ac) {
   5651    for (uint32_t i = 0; i < mEnabledSensors.Length(); i++)
   5652      ac->AddWindowListener(mEnabledSensors[i], this);
   5653  }
   5654  EnableGamepadUpdates();
   5655  EnableVRUpdates();
   5656 
   5657  // Resume all of the AudioContexts for this window
   5658  for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
   5659    mAudioContexts[i]->ResumeFromChrome();
   5660  }
   5661 
   5662  if (RefPtr<MediaDevices> devices = GetExtantMediaDevices()) {
   5663    devices->WindowResumed();
   5664  }
   5665 
   5666  mTimeoutManager->Resume();
   5667 
   5668  ResumeIdleRequests();
   5669 
   5670  // Resume all of the workers for this window.  We must do this
   5671  // after timeouts since workers may have queued events that can trigger
   5672  // a setTimeout().
   5673  ResumeWorkersForWindow(*this);
   5674 
   5675  for (RefPtr<mozilla::dom::SharedWorker> pinnedWorker :
   5676       mSharedWorkers.ForwardRange()) {
   5677    pinnedWorker->Resume();
   5678  }
   5679 
   5680  if (mWindowGlobalChild) {
   5681    mWindowGlobalChild->UnblockBFCacheFor(BFCacheStatus::SUSPENDED);
   5682  }
   5683 }
   5684 
   5685 bool nsGlobalWindowInner::IsSuspended() const {
   5686  MOZ_ASSERT(NS_IsMainThread());
   5687  return mSuspendDepth != 0;
   5688 }
   5689 
   5690 void nsGlobalWindowInner::Freeze(bool aIncludeSubWindows) {
   5691  MOZ_ASSERT(NS_IsMainThread());
   5692  Suspend(aIncludeSubWindows);
   5693  FreezeInternal(aIncludeSubWindows);
   5694 }
   5695 
   5696 void nsGlobalWindowInner::FreezeInternal(bool aIncludeSubWindows) {
   5697  MOZ_ASSERT(NS_IsMainThread());
   5698  MOZ_DIAGNOSTIC_ASSERT(IsCurrentInnerWindow());
   5699  MOZ_DIAGNOSTIC_ASSERT(IsSuspended());
   5700 
   5701  HintIsLoading(false);
   5702 
   5703  if (aIncludeSubWindows) {
   5704    CallOnInProcessChildren(&nsGlobalWindowInner::FreezeInternal,
   5705                            aIncludeSubWindows);
   5706  }
   5707 
   5708  mFreezeDepth += 1;
   5709  MOZ_ASSERT(mSuspendDepth >= mFreezeDepth);
   5710  if (mFreezeDepth != 1) {
   5711    return;
   5712  }
   5713 
   5714  FreezeWorkersForWindow(*this);
   5715 
   5716  for (RefPtr<mozilla::dom::SharedWorker> pinnedWorker :
   5717       mSharedWorkers.ForwardRange()) {
   5718    pinnedWorker->Freeze();
   5719  }
   5720 
   5721  mTimeoutManager->Freeze();
   5722  if (mClientSource) {
   5723    mClientSource->Freeze();
   5724  }
   5725 
   5726  NotifyGlobalFrozen();
   5727 }
   5728 
   5729 void nsGlobalWindowInner::Thaw(bool aIncludeSubWindows) {
   5730  MOZ_ASSERT(NS_IsMainThread());
   5731  ThawInternal(aIncludeSubWindows);
   5732  Resume(aIncludeSubWindows);
   5733 }
   5734 
   5735 void nsGlobalWindowInner::ThawInternal(bool aIncludeSubWindows) {
   5736  MOZ_ASSERT(NS_IsMainThread());
   5737  MOZ_DIAGNOSTIC_ASSERT(IsCurrentInnerWindow());
   5738  MOZ_DIAGNOSTIC_ASSERT(IsSuspended());
   5739 
   5740  if (aIncludeSubWindows) {
   5741    CallOnInProcessChildren(&nsGlobalWindowInner::ThawInternal,
   5742                            aIncludeSubWindows);
   5743  }
   5744 
   5745  MOZ_ASSERT(mFreezeDepth != 0);
   5746  mFreezeDepth -= 1;
   5747  MOZ_ASSERT(mSuspendDepth >= mFreezeDepth);
   5748  if (mFreezeDepth != 0) {
   5749    return;
   5750  }
   5751 
   5752  if (mClientSource) {
   5753    mClientSource->Thaw();
   5754  }
   5755  mTimeoutManager->Thaw();
   5756 
   5757  ThawWorkersForWindow(*this);
   5758 
   5759  for (RefPtr<mozilla::dom::SharedWorker> pinnedWorker :
   5760       mSharedWorkers.ForwardRange()) {
   5761    pinnedWorker->Thaw();
   5762  }
   5763 
   5764  NotifyGlobalThawed();
   5765 }
   5766 
   5767 bool nsGlobalWindowInner::IsFrozen() const {
   5768  MOZ_ASSERT(NS_IsMainThread());
   5769  bool frozen = mFreezeDepth != 0;
   5770  MOZ_ASSERT_IF(frozen, IsSuspended());
   5771  return frozen;
   5772 }
   5773 
   5774 void nsGlobalWindowInner::SyncStateFromParentWindow() {
   5775  // This method should only be called on an inner window that has been
   5776  // assigned to an outer window already.
   5777  MOZ_ASSERT(IsCurrentInnerWindow());
   5778  nsPIDOMWindowOuter* outer = GetOuterWindow();
   5779  MOZ_ASSERT(outer);
   5780 
   5781  // Attempt to find our parent windows.
   5782  nsCOMPtr<Element> frame = outer->GetFrameElementInternal();
   5783  nsPIDOMWindowOuter* parentOuter =
   5784      frame ? frame->OwnerDoc()->GetWindow() : nullptr;
   5785  nsGlobalWindowInner* parentInner =
   5786      parentOuter
   5787          ? nsGlobalWindowInner::Cast(parentOuter->GetCurrentInnerWindow())
   5788          : nullptr;
   5789 
   5790  // If our outer is in a modal state, but our parent is not in a modal
   5791  // state, then we must apply the suspend directly.  If our parent is
   5792  // in a modal state then we should get the suspend automatically
   5793  // via the parentSuspendDepth application below.
   5794  if ((!parentInner || !parentInner->IsInModalState()) && IsInModalState()) {
   5795    Suspend();
   5796  }
   5797 
   5798  uint32_t parentFreezeDepth = parentInner ? parentInner->mFreezeDepth : 0;
   5799  uint32_t parentSuspendDepth = parentInner ? parentInner->mSuspendDepth : 0;
   5800 
   5801  // Since every Freeze() calls Suspend(), the suspend count must
   5802  // be equal or greater to the freeze count.
   5803  MOZ_ASSERT(parentFreezeDepth <= parentSuspendDepth);
   5804 
   5805  // First apply the Freeze() calls.
   5806  for (uint32_t i = 0; i < parentFreezeDepth; ++i) {
   5807    Freeze();
   5808  }
   5809 
   5810  // Now apply only the number of Suspend() calls to reach the target
   5811  // suspend count after applying the Freeze() calls.
   5812  for (uint32_t i = 0; i < (parentSuspendDepth - parentFreezeDepth); ++i) {
   5813    Suspend();
   5814  }
   5815 }
   5816 
   5817 void nsGlobalWindowInner::UpdateBackgroundState() {
   5818  if (RefPtr<MediaDevices> devices = GetExtantMediaDevices()) {
   5819    devices->BackgroundStateChanged();
   5820  }
   5821  mTimeoutManager->UpdateBackgroundState();
   5822 
   5823  UpdateWorkersBackgroundState(*this, IsBackgroundInternal());
   5824 }
   5825 
   5826 template <typename Method, typename... Args>
   5827 CallState nsGlobalWindowInner::CallOnInProcessDescendantsInternal(
   5828    BrowsingContext* aBrowsingContext, bool aChildOnly, Method aMethod,
   5829    Args&&... aArgs) {
   5830  MOZ_ASSERT(NS_IsMainThread());
   5831  MOZ_ASSERT(aBrowsingContext);
   5832 
   5833  CallState state = CallState::Continue;
   5834  for (const RefPtr<BrowsingContext>& bc : aBrowsingContext->Children()) {
   5835    if (nsCOMPtr<nsPIDOMWindowOuter> pWin = bc->GetDOMWindow()) {
   5836      auto* win = nsGlobalWindowOuter::Cast(pWin);
   5837      if (nsGlobalWindowInner* inner =
   5838              nsGlobalWindowInner::Cast(win->GetCurrentInnerWindow())) {
   5839        // Call the descendant method using our helper CallDescendant() template
   5840        // method. This allows us to handle both void returning methods and
   5841        // methods that return CallState explicitly.  For void returning methods
   5842        // we assume CallState::Continue.
   5843        using returnType = decltype((inner->*aMethod)(aArgs...));
   5844        state = CallDescendant<returnType>(inner, aMethod, aArgs...);
   5845 
   5846        if (state == CallState::Stop) {
   5847          return state;
   5848        }
   5849      }
   5850    }
   5851 
   5852    if (!aChildOnly) {
   5853      state = CallOnInProcessDescendantsInternal(bc.get(), aChildOnly, aMethod,
   5854                                                 aArgs...);
   5855      if (state == CallState::Stop) {
   5856        return state;
   5857      }
   5858    }
   5859  }
   5860 
   5861  return state;
   5862 }
   5863 
   5864 nsIURI* nsGlobalWindowInner::GetBaseURI() const { return GetDocBaseURI(); }
   5865 
   5866 Maybe<ClientInfo> nsGlobalWindowInner::GetClientInfo() const {
   5867  MOZ_ASSERT(NS_IsMainThread());
   5868  if (mDoc && mDoc->IsStaticDocument()) {
   5869    if (Maybe<ClientInfo> info = mDoc->GetOriginalDocument()->GetClientInfo()) {
   5870      return info;
   5871    }
   5872  }
   5873 
   5874  Maybe<ClientInfo> clientInfo;
   5875  if (mClientSource) {
   5876    clientInfo.emplace(mClientSource->Info());
   5877  }
   5878  return clientInfo;
   5879 }
   5880 
   5881 Maybe<ClientState> nsGlobalWindowInner::GetClientState() const {
   5882  MOZ_ASSERT(NS_IsMainThread());
   5883  if (mDoc && mDoc->IsStaticDocument()) {
   5884    if (Maybe<ClientState> state =
   5885            mDoc->GetOriginalDocument()->GetClientState()) {
   5886      return state;
   5887    }
   5888  }
   5889 
   5890  Maybe<ClientState> clientState;
   5891  if (mClientSource) {
   5892    Result<ClientState, ErrorResult> res = mClientSource->SnapshotState();
   5893    if (res.isOk()) {
   5894      clientState.emplace(res.unwrap());
   5895    } else {
   5896      res.unwrapErr().SuppressException();
   5897    }
   5898  }
   5899  return clientState;
   5900 }
   5901 
   5902 Maybe<ServiceWorkerDescriptor> nsGlobalWindowInner::GetController() const {
   5903  MOZ_ASSERT(NS_IsMainThread());
   5904  if (mDoc && mDoc->IsStaticDocument()) {
   5905    if (Maybe<ServiceWorkerDescriptor> controller =
   5906            mDoc->GetOriginalDocument()->GetController()) {
   5907      return controller;
   5908    }
   5909  }
   5910 
   5911  Maybe<ServiceWorkerDescriptor> controller;
   5912  if (mClientSource) {
   5913    controller = mClientSource->GetController();
   5914  }
   5915  return controller;
   5916 }
   5917 
   5918 void nsGlobalWindowInner::SetPolicyContainer(
   5919    nsIPolicyContainer* aPolicyContainer) {
   5920  if (!mClientSource) {
   5921    return;
   5922  }
   5923  mClientSource->SetPolicyContainer(aPolicyContainer);
   5924  // Also cache the PolicyContainer within the document
   5925  mDoc->SetPolicyContainer(aPolicyContainer);
   5926 
   5927  if (mWindowGlobalChild) {
   5928    mWindowGlobalChild->SendSetClientInfo(mClientSource->Info().ToIPC());
   5929  }
   5930 }
   5931 
   5932 nsIPolicyContainer* nsGlobalWindowInner::GetPolicyContainer() {
   5933  if (mDoc) {
   5934    return mDoc->GetPolicyContainer();
   5935  }
   5936 
   5937  // If the window is partially torn down and has its document nulled out,
   5938  // we query the policy container we snapshot in FreeInnerObjects.
   5939  if (mDocumentPolicyContainer) {
   5940    return mDocumentPolicyContainer;
   5941  }
   5942  return nullptr;
   5943 }
   5944 
   5945 void nsGlobalWindowInner::SetPreloadCsp(nsIContentSecurityPolicy* aPreloadCsp) {
   5946  if (!mClientSource) {
   5947    return;
   5948  }
   5949  mClientSource->SetPreloadCsp(aPreloadCsp);
   5950  // Also cache the preload CSP within the document
   5951  mDoc->SetPreloadCsp(aPreloadCsp);
   5952 
   5953  if (mWindowGlobalChild) {
   5954    mWindowGlobalChild->SendSetClientInfo(mClientSource->Info().ToIPC());
   5955  }
   5956 }
   5957 
   5958 already_AddRefed<ServiceWorkerContainer>
   5959 nsGlobalWindowInner::GetServiceWorkerContainer() {
   5960  return Navigator()->ServiceWorker();
   5961 }
   5962 
   5963 RefPtr<ServiceWorker> nsGlobalWindowInner::GetOrCreateServiceWorker(
   5964    const ServiceWorkerDescriptor& aDescriptor) {
   5965  MOZ_ASSERT(NS_IsMainThread());
   5966  RefPtr<ServiceWorker> ref;
   5967  ForEachGlobalTeardownObserver(
   5968      [&](GlobalTeardownObserver* aObserver, bool* aDoneOut) {
   5969        RefPtr<ServiceWorker> sw = do_QueryObject(aObserver);
   5970        if (!sw || !sw->Descriptor().Matches(aDescriptor)) {
   5971          return;
   5972        }
   5973 
   5974        ref = std::move(sw);
   5975        *aDoneOut = true;
   5976      });
   5977 
   5978  if (!ref) {
   5979    ref = ServiceWorker::Create(this, aDescriptor);
   5980  }
   5981 
   5982  return ref;
   5983 }
   5984 
   5985 RefPtr<mozilla::dom::ServiceWorkerRegistration>
   5986 nsGlobalWindowInner::GetServiceWorkerRegistration(
   5987    const mozilla::dom::ServiceWorkerRegistrationDescriptor& aDescriptor)
   5988    const {
   5989  MOZ_ASSERT(NS_IsMainThread());
   5990  RefPtr<ServiceWorkerRegistration> ref;
   5991  ForEachGlobalTeardownObserver(
   5992      [&](GlobalTeardownObserver* aObserver, bool* aDoneOut) {
   5993        RefPtr<ServiceWorkerRegistration> swr = do_QueryObject(aObserver);
   5994        if (!swr || !swr->MatchesDescriptor(aDescriptor)) {
   5995          return;
   5996        }
   5997 
   5998        ref = std::move(swr);
   5999        *aDoneOut = true;
   6000      });
   6001  return ref;
   6002 }
   6003 
   6004 RefPtr<ServiceWorkerRegistration>
   6005 nsGlobalWindowInner::GetOrCreateServiceWorkerRegistration(
   6006    const ServiceWorkerRegistrationDescriptor& aDescriptor) {
   6007  MOZ_ASSERT(NS_IsMainThread());
   6008  RefPtr<ServiceWorkerRegistration> ref =
   6009      GetServiceWorkerRegistration(aDescriptor);
   6010  if (!ref) {
   6011    ref = ServiceWorkerRegistration::CreateForMainThread(this, aDescriptor);
   6012  }
   6013  return ref;
   6014 }
   6015 
   6016 StorageAccess nsGlobalWindowInner::GetStorageAccess() {
   6017  return StorageAllowedForWindow(this);
   6018 }
   6019 
   6020 nsICookieJarSettings* nsGlobalWindowInner::GetCookieJarSettings() {
   6021  MOZ_ASSERT(NS_IsMainThread());
   6022  if (mDoc) {
   6023    return mDoc->CookieJarSettings();
   6024  }
   6025  return nullptr;
   6026 }
   6027 
   6028 nsresult nsGlobalWindowInner::FireDelayedDOMEvents(bool aIncludeSubWindows) {
   6029  // Fires an offline status event if the offline status has changed
   6030  FireOfflineStatusEventIfChanged();
   6031 
   6032  if (mCookieStore) {
   6033    mCookieStore->FireDelayedDOMEvents();
   6034  }
   6035 
   6036  if (!aIncludeSubWindows) {
   6037    return NS_OK;
   6038  }
   6039 
   6040  nsCOMPtr<nsIDocShell> docShell = GetDocShell();
   6041  if (docShell) {
   6042    int32_t childCount = 0;
   6043    docShell->GetInProcessChildCount(&childCount);
   6044 
   6045    // Take a copy of the current children so that modifications to
   6046    // the child list don't affect to the iteration.
   6047    AutoTArray<nsCOMPtr<nsIDocShellTreeItem>, 8> children;
   6048    for (int32_t i = 0; i < childCount; ++i) {
   6049      nsCOMPtr<nsIDocShellTreeItem> childShell;
   6050      docShell->GetInProcessChildAt(i, getter_AddRefs(childShell));
   6051      if (childShell) {
   6052        children.AppendElement(childShell);
   6053      }
   6054    }
   6055 
   6056    for (nsCOMPtr<nsIDocShellTreeItem> childShell : children) {
   6057      if (nsCOMPtr<nsPIDOMWindowOuter> pWin = childShell->GetWindow()) {
   6058        auto* win = nsGlobalWindowOuter::Cast(pWin);
   6059        win->FireDelayedDOMEvents(true);
   6060      }
   6061    }
   6062  }
   6063 
   6064  return NS_OK;
   6065 }
   6066 
   6067 //*****************************************************************************
   6068 // nsGlobalWindowInner: Window Control Functions
   6069 //*****************************************************************************
   6070 
   6071 nsPIDOMWindowOuter* nsGlobalWindowInner::GetInProcessParentInternal() {
   6072  nsGlobalWindowOuter* outer = GetOuterWindowInternal();
   6073  if (!outer) {
   6074    // No outer window available!
   6075    return nullptr;
   6076  }
   6077  return outer->GetInProcessParentInternal();
   6078 }
   6079 
   6080 nsIPrincipal* nsGlobalWindowInner::GetTopLevelAntiTrackingPrincipal() {
   6081  nsPIDOMWindowOuter* outerWindow = GetOuterWindowInternal();
   6082  if (!outerWindow) {
   6083    return nullptr;
   6084  }
   6085 
   6086  nsPIDOMWindowOuter* topLevelOuterWindow =
   6087      GetBrowsingContext()->Top()->GetDOMWindow();
   6088  if (!topLevelOuterWindow) {
   6089    return nullptr;
   6090  }
   6091 
   6092  bool stopAtOurLevel =
   6093      mDoc && mDoc->CookieJarSettings()->GetCookieBehavior() ==
   6094                  nsICookieService::BEHAVIOR_REJECT_TRACKER;
   6095 
   6096  if (stopAtOurLevel && topLevelOuterWindow == outerWindow) {
   6097    return nullptr;
   6098  }
   6099 
   6100  nsPIDOMWindowInner* topLevelInnerWindow =
   6101      topLevelOuterWindow->GetCurrentInnerWindow();
   6102  if (NS_WARN_IF(!topLevelInnerWindow)) {
   6103    return nullptr;
   6104  }
   6105 
   6106  nsIPrincipal* topLevelPrincipal =
   6107      nsGlobalWindowInner::Cast(topLevelInnerWindow)->GetPrincipal();
   6108  if (NS_WARN_IF(!topLevelPrincipal)) {
   6109    return nullptr;
   6110  }
   6111 
   6112  return topLevelPrincipal;
   6113 }
   6114 
   6115 nsIPrincipal* nsGlobalWindowInner::GetClientPrincipal() {
   6116  return mClientSource ? mClientSource->GetPrincipal() : nullptr;
   6117 }
   6118 
   6119 bool nsGlobalWindowInner::IsInFullScreenTransition() {
   6120  if (!mIsChrome) {
   6121    return false;
   6122  }
   6123 
   6124  nsGlobalWindowOuter* outerWindow = GetOuterWindowInternal();
   6125  if (!outerWindow) {
   6126    return false;
   6127  }
   6128 
   6129  return outerWindow->mIsInFullScreenTransition;
   6130 }
   6131 
   6132 //*****************************************************************************
   6133 // nsGlobalWindowInner: Timeout Functions
   6134 //*****************************************************************************
   6135 
   6136 class WindowScriptTimeoutHandler final : public ScriptTimeoutHandler {
   6137 public:
   6138  NS_DECL_ISUPPORTS_INHERITED
   6139  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(WindowScriptTimeoutHandler,
   6140                                           ScriptTimeoutHandler)
   6141 
   6142  WindowScriptTimeoutHandler(JSContext* aCx, nsIGlobalObject* aGlobal,
   6143                             const nsAString& aExpression)
   6144      : ScriptTimeoutHandler(aCx, aGlobal, aExpression),
   6145        mInitiatingScript(ScriptLoader::GetActiveScript(aCx)) {}
   6146 
   6147  MOZ_CAN_RUN_SCRIPT virtual bool Call(const char* aExecutionReason) override;
   6148 
   6149 private:
   6150  virtual ~WindowScriptTimeoutHandler() = default;
   6151 
   6152  // Initiating script for use when evaluating mExpr on the main thread.
   6153  RefPtr<JS::loader::LoadedScript> mInitiatingScript;
   6154 };
   6155 
   6156 NS_IMPL_CYCLE_COLLECTION_INHERITED(WindowScriptTimeoutHandler,
   6157                                   ScriptTimeoutHandler, mInitiatingScript)
   6158 
   6159 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WindowScriptTimeoutHandler)
   6160 NS_INTERFACE_MAP_END_INHERITING(ScriptTimeoutHandler)
   6161 
   6162 NS_IMPL_ADDREF_INHERITED(WindowScriptTimeoutHandler, ScriptTimeoutHandler)
   6163 NS_IMPL_RELEASE_INHERITED(WindowScriptTimeoutHandler, ScriptTimeoutHandler)
   6164 
   6165 bool WindowScriptTimeoutHandler::Call(const char* aExecutionReason) {
   6166  // New script entry point required, due to the "Create a script" sub-step
   6167  // of
   6168  // http://www.whatwg.org/specs/web-apps/current-work/#timer-initialisation-steps
   6169  nsAutoMicroTask mt;
   6170  AutoEntryScript aes(mGlobal, aExecutionReason, true);
   6171  JS::CompileOptions options(aes.cx());
   6172  options.setFileAndLine(mCaller.FileName().get(), mCaller.mLine);
   6173  options.setNoScriptRval(true);
   6174  options.setIntroductionType("domTimer");
   6175  JS::Rooted<JSObject*> global(aes.cx(), mGlobal->GetGlobalJSObject());
   6176  {
   6177    if (MOZ_UNLIKELY(!xpc::Scriptability::Get(global).Allowed())) {
   6178      return true;
   6179    }
   6180 
   6181    IgnoredErrorResult erv;
   6182    mozilla::AutoProfilerLabel autoProfilerLabel("JSExecutionContext",
   6183                                                 /* dynamicStr */ nullptr,
   6184                                                 JS::ProfilingCategoryPair::JS);
   6185    JSAutoRealm autoRealm(aes.cx(), global);
   6186    RefPtr<JS::Stencil> stencil;
   6187    JS::Rooted<JSScript*> script(aes.cx());
   6188    Compile(aes.cx(), options, mExpr, stencil, erv);
   6189    if (stencil) {
   6190      JS::InstantiateOptions instantiateOptions(options);
   6191      MOZ_ASSERT(!instantiateOptions.deferDebugMetadata);
   6192      script.set(JS::InstantiateGlobalStencil(aes.cx(), instantiateOptions,
   6193                                              stencil, /* storage */ nullptr));
   6194      if (!script) {
   6195        erv.NoteJSContextException(aes.cx());
   6196      }
   6197    }
   6198 
   6199    if (script) {
   6200      MOZ_ASSERT(!erv.Failed());
   6201      if (mInitiatingScript) {
   6202        mInitiatingScript->AssociateWithScript(script);
   6203      }
   6204 
   6205      if (!JS_ExecuteScript(aes.cx(), script)) {
   6206        erv.NoteJSContextException(aes.cx());
   6207      }
   6208    }
   6209 
   6210    if (erv.IsUncatchableException()) {
   6211      return false;
   6212    }
   6213  }
   6214 
   6215  return true;
   6216 };
   6217 
   6218 nsGlobalWindowInner* nsGlobalWindowInner::InnerForSetTimeoutOrInterval(
   6219    ErrorResult& aError) {
   6220  nsGlobalWindowOuter* outer = GetOuterWindowInternal();
   6221  nsPIDOMWindowInner* currentInner =
   6222      outer ? outer->GetCurrentInnerWindow() : this;
   6223 
   6224  // If forwardTo is not the window with an active document then we want the
   6225  // call to setTimeout/Interval to be a noop, so return null but don't set an
   6226  // error.
   6227  return HasActiveDocument() ? nsGlobalWindowInner::Cast(currentInner)
   6228                             : nullptr;
   6229 }
   6230 
   6231 int32_t nsGlobalWindowInner::SetTimeout(
   6232    JSContext* aCx, const FunctionOrTrustedScriptOrString& aHandler,
   6233    int32_t aTimeout, const Sequence<JS::Value>& aArguments,
   6234    nsIPrincipal* aSubjectPrincipal, ErrorResult& aError) {
   6235  return SetTimeoutOrInterval(aCx, aHandler, aTimeout, aArguments, false,
   6236                              aSubjectPrincipal, aError);
   6237 }
   6238 
   6239 int32_t nsGlobalWindowInner::SetInterval(
   6240    JSContext* aCx, const FunctionOrTrustedScriptOrString& aHandler,
   6241    const int32_t aTimeout, const Sequence<JS::Value>& aArguments,
   6242    nsIPrincipal* aSubjectPrincipal, ErrorResult& aError) {
   6243  return SetTimeoutOrInterval(aCx, aHandler, aTimeout, aArguments, true,
   6244                              aSubjectPrincipal, aError);
   6245 }
   6246 
   6247 int32_t nsGlobalWindowInner::SetTimeoutOrInterval(
   6248    JSContext* aCx, const FunctionOrTrustedScriptOrString& aHandler,
   6249    int32_t aTimeout, const Sequence<JS::Value>& aArguments, bool aIsInterval,
   6250    nsIPrincipal* aSubjectPrincipal, ErrorResult& aError) {
   6251  nsGlobalWindowInner* inner = InnerForSetTimeoutOrInterval(aError);
   6252  if (!inner) {
   6253    return -1;
   6254  }
   6255 
   6256  if (inner != this) {
   6257    RefPtr<nsGlobalWindowInner> innerRef(inner);
   6258    return innerRef->SetTimeoutOrInterval(aCx, aHandler, aTimeout, aArguments,
   6259                                          aIsInterval, aSubjectPrincipal,
   6260                                          aError);
   6261  }
   6262 
   6263  DebuggerNotificationDispatch(
   6264      this, aIsInterval ? DebuggerNotificationType::SetInterval
   6265                        : DebuggerNotificationType::SetTimeout);
   6266 
   6267  if (!GetContextInternal() || !HasJSGlobal()) {
   6268    // This window was already closed, or never properly initialized,
   6269    // don't let a timer be scheduled on such a window.
   6270    aError.Throw(NS_ERROR_NOT_INITIALIZED);
   6271    return 0;
   6272  }
   6273 
   6274  if (aHandler.IsFunction()) {
   6275    nsTArray<JS::Heap<JS::Value>> args;
   6276    if (!args.AppendElements(aArguments, fallible)) {
   6277      aError.Throw(NS_ERROR_OUT_OF_MEMORY);
   6278      return 0;
   6279    }
   6280 
   6281    RefPtr<TimeoutHandler> handler = new CallbackTimeoutHandler(
   6282        aCx, this, &aHandler.GetAsFunction(), std::move(args));
   6283 
   6284    int32_t result;
   6285    aError = mTimeoutManager->SetTimeout(handler, aTimeout, aIsInterval,
   6286                                         Timeout::Reason::eTimeoutOrInterval,
   6287                                         &result);
   6288    return result;
   6289  }
   6290 
   6291  constexpr nsLiteralString sinkSetTimeout = u"Window setTimeout"_ns;
   6292  constexpr nsLiteralString sinkSetInterval = u"Window setInterval"_ns;
   6293  Maybe<nsAutoString> compliantStringHolder;
   6294  nsCOMPtr<nsIGlobalObject> pinnedGlobal = this;
   6295  const nsAString* compliantString =
   6296      TrustedTypeUtils::GetTrustedTypesCompliantString(
   6297          aHandler, aIsInterval ? sinkSetInterval : sinkSetTimeout,
   6298          kTrustedTypesOnlySinkGroup, *pinnedGlobal, aSubjectPrincipal,
   6299          compliantStringHolder, aError);
   6300  if (aError.Failed()) {
   6301    return 0;
   6302  }
   6303 
   6304  bool allowEval = false;
   6305  aError =
   6306      CSPEvalChecker::CheckForWindow(aCx, this, *compliantString, &allowEval);
   6307  if (NS_WARN_IF(aError.Failed()) || !allowEval) {
   6308    return 0;
   6309  }
   6310  RefPtr<TimeoutHandler> handler =
   6311      new WindowScriptTimeoutHandler(aCx, this, *compliantString);
   6312  int32_t result;
   6313  aError =
   6314      mTimeoutManager->SetTimeout(handler, aTimeout, aIsInterval,
   6315                                  Timeout::Reason::eTimeoutOrInterval, &result);
   6316  return result;
   6317 }
   6318 
   6319 static const char* GetTimeoutReasonString(Timeout* aTimeout) {
   6320  switch (aTimeout->mReason) {
   6321    case Timeout::Reason::eTimeoutOrInterval:
   6322      if (aTimeout->mIsInterval) {
   6323        return "setInterval handler";
   6324      }
   6325      return "setTimeout handler";
   6326    case Timeout::Reason::eIdleCallbackTimeout:
   6327      return "setIdleCallback handler (timed out)";
   6328    case Timeout::Reason::eAbortSignalTimeout:
   6329      return "AbortSignal timeout";
   6330    case Timeout::Reason::eDelayedWebTaskTimeout:
   6331      return "delayedWebTaskCallback handler (timed out)";
   6332    case Timeout::Reason::eJSTimeout:
   6333      return "JavaScript TimeoutJob (timed out)";
   6334    default:
   6335      MOZ_CRASH("Unexpected enum value");
   6336      return "";
   6337  }
   6338  MOZ_CRASH("Unexpected enum value");
   6339  return "";
   6340 }
   6341 
   6342 bool nsGlobalWindowInner::RunTimeoutHandler(Timeout* aTimeout) {
   6343  // Hold on to the timeout in case mExpr or mFunObj releases its
   6344  // doc.
   6345  // XXXbz Our caller guarantees it'll hold on to the timeout (because
   6346  // we're MOZ_CAN_RUN_SCRIPT), so we can probably stop doing that...
   6347  RefPtr<Timeout> timeout = aTimeout;
   6348  Timeout* last_running_timeout = mTimeoutManager->BeginRunningTimeout(timeout);
   6349  timeout->mRunning = true;
   6350 
   6351  // Push this timeout's popup control state, which should only be
   6352  // enabled the first time a timeout fires that was created while
   6353  // popups were enabled and with a delay less than
   6354  // "dom.disable_open_click_delay".
   6355  AutoPopupStatePusher popupStatePusher(timeout->mPopupState);
   6356 
   6357  // Clear the timeout's popup state, if any, to prevent interval
   6358  // timeouts from repeatedly opening poups.
   6359  timeout->mPopupState = PopupBlocker::openAbused;
   6360 
   6361  uint32_t nestingLevel = mTimeoutManager->GetNestingLevelForWindow();
   6362  mTimeoutManager->SetNestingLevelForWindow(timeout->mNestingLevel);
   6363 
   6364  const char* reason = GetTimeoutReasonString(timeout);
   6365 
   6366  nsCString str;
   6367  if (profiler_thread_is_being_profiled_for_markers()) {
   6368    TimeDuration originalInterval = timeout->When() - timeout->SubmitTime();
   6369    str.Append(reason);
   6370    str.Append(" with interval ");
   6371    str.AppendInt(int(originalInterval.ToMilliseconds()));
   6372    str.Append("ms: ");
   6373    nsCString handlerDescription;
   6374    timeout->mScriptHandler->GetDescription(handlerDescription);
   6375    str.Append(handlerDescription);
   6376  }
   6377  AUTO_PROFILER_MARKER_TEXT("setTimeout callback", DOM,
   6378                            MarkerOptions(MarkerStack::TakeBacktrace(
   6379                                              timeout->TakeProfilerBacktrace()),
   6380                                          MarkerInnerWindowId(mWindowID)),
   6381                            str);
   6382 
   6383  bool abortIntervalHandler;
   6384  {
   6385    RefPtr<TimeoutHandler> handler(timeout->mScriptHandler);
   6386 
   6387    CallbackDebuggerNotificationGuard guard(
   6388        this, timeout->mIsInterval
   6389                  ? DebuggerNotificationType::SetIntervalCallback
   6390                  : DebuggerNotificationType::SetTimeoutCallback);
   6391    abortIntervalHandler = !handler->Call(reason);
   6392  }
   6393 
   6394  // If we received an uncatchable exception, do not schedule the timeout again.
   6395  // This allows the slow script dialog to break easy DoS attacks like
   6396  // setInterval(function() { while(1); }, 100);
   6397  if (abortIntervalHandler) {
   6398    // If it wasn't an interval timer to begin with, this does nothing.  If it
   6399    // was, we'll treat it as a timeout that we just ran and discard it when
   6400    // we return.
   6401    timeout->mIsInterval = false;
   6402  }
   6403 
   6404  // We ignore any failures from calling EvaluateString() on the context or
   6405  // Call() on a Function here since we're in a loop
   6406  // where we're likely to be running timeouts whose OS timers
   6407  // didn't fire in time and we don't want to not fire those timers
   6408  // now just because execution of one timer failed. We can't
   6409  // propagate the error to anyone who cares about it from this
   6410  // point anyway, and the script context should have already reported
   6411  // the script error in the usual way - so we just drop it.
   6412 
   6413  mTimeoutManager->SetNestingLevelForWindow(nestingLevel);
   6414 
   6415  mTimeoutManager->EndRunningTimeout(last_running_timeout);
   6416  timeout->mRunning = false;
   6417 
   6418  return timeout->mCleared;
   6419 }
   6420 
   6421 //*****************************************************************************
   6422 // nsGlobalWindowInner: Helper Functions
   6423 //*****************************************************************************
   6424 
   6425 already_AddRefed<nsIDocShellTreeOwner> nsGlobalWindowInner::GetTreeOwner() {
   6426  FORWARD_TO_OUTER(GetTreeOwner, (), nullptr);
   6427 }
   6428 
   6429 already_AddRefed<nsIWebBrowserChrome>
   6430 nsGlobalWindowInner::GetWebBrowserChrome() {
   6431  nsCOMPtr<nsIDocShellTreeOwner> treeOwner = GetTreeOwner();
   6432 
   6433  nsCOMPtr<nsIWebBrowserChrome> browserChrome = do_GetInterface(treeOwner);
   6434  return browserChrome.forget();
   6435 }
   6436 
   6437 ScrollContainerFrame* nsGlobalWindowInner::GetScrollContainerFrame() {
   6438  FORWARD_TO_OUTER(GetScrollContainerFrame, (), nullptr);
   6439 }
   6440 
   6441 bool nsGlobalWindowInner::IsPrivateBrowsing() {
   6442  nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(GetDocShell());
   6443  return loadContext && loadContext->UsePrivateBrowsing();
   6444 }
   6445 
   6446 void nsGlobalWindowInner::FlushPendingNotifications(FlushType aType) {
   6447  if (mDoc) {
   6448    mDoc->FlushPendingNotifications(aType);
   6449  }
   6450 }
   6451 
   6452 void nsGlobalWindowInner::EnableDeviceSensor(uint32_t aType) {
   6453  bool alreadyEnabled = false;
   6454  for (uint32_t i = 0; i < mEnabledSensors.Length(); i++) {
   6455    if (mEnabledSensors[i] == aType) {
   6456      alreadyEnabled = true;
   6457      break;
   6458    }
   6459  }
   6460 
   6461  mEnabledSensors.AppendElement(aType);
   6462 
   6463  if (alreadyEnabled) {
   6464    return;
   6465  }
   6466 
   6467  nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
   6468  if (ac) {
   6469    ac->AddWindowListener(aType, this);
   6470  }
   6471 }
   6472 
   6473 void nsGlobalWindowInner::DisableDeviceSensor(uint32_t aType) {
   6474  int32_t doomedElement = -1;
   6475  int32_t listenerCount = 0;
   6476  for (uint32_t i = 0; i < mEnabledSensors.Length(); i++) {
   6477    if (mEnabledSensors[i] == aType) {
   6478      doomedElement = i;
   6479      listenerCount++;
   6480    }
   6481  }
   6482 
   6483  if (doomedElement == -1) {
   6484    return;
   6485  }
   6486 
   6487  mEnabledSensors.RemoveElementAt(doomedElement);
   6488 
   6489  if (listenerCount > 1) {
   6490    return;
   6491  }
   6492 
   6493  nsCOMPtr<nsIDeviceSensors> ac = do_GetService(NS_DEVICE_SENSORS_CONTRACTID);
   6494  if (ac) {
   6495    ac->RemoveWindowListener(aType, this);
   6496  }
   6497 }
   6498 
   6499 #if defined(MOZ_WIDGET_ANDROID)
   6500 void nsGlobalWindowInner::EnableOrientationChangeListener() {
   6501  if (!ShouldResistFingerprinting(RFPTarget::ScreenOrientation)) {
   6502    mHasOrientationChangeListeners = true;
   6503    mOrientationAngle = Orientation(CallerType::System);
   6504  }
   6505 }
   6506 
   6507 void nsGlobalWindowInner::DisableOrientationChangeListener() {
   6508  mHasOrientationChangeListeners = false;
   6509 }
   6510 #endif
   6511 
   6512 void nsGlobalWindowInner::SetHasGamepadEventListener(
   6513    bool aHasGamepad /* = true*/) {
   6514  mHasGamepad = aHasGamepad;
   6515  if (aHasGamepad) {
   6516    EnableGamepadUpdates();
   6517  }
   6518 }
   6519 
   6520 void nsGlobalWindowInner::NotifyDetectXRRuntimesCompleted() {
   6521  if (!mXRRuntimeDetectionInFlight) {
   6522    return;
   6523  }
   6524  mXRRuntimeDetectionInFlight = false;
   6525  if (mXRPermissionRequestInFlight) {
   6526    return;
   6527  }
   6528  gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
   6529  bool supported = vm->RuntimeSupportsVR();
   6530  if (!supported) {
   6531    // A VR runtime was not installed; we can suppress
   6532    // the permission prompt
   6533    OnXRPermissionRequestCancel();
   6534    return;
   6535  }
   6536  // A VR runtime was found.  Display a permission prompt before
   6537  // allowing it to be accessed.
   6538  // Connect to the VRManager in order to receive the runtime
   6539  // detection results.
   6540  mXRPermissionRequestInFlight = true;
   6541  RefPtr<XRPermissionRequest> request =
   6542      new XRPermissionRequest(this, WindowID());
   6543  (void)NS_WARN_IF(NS_FAILED(request->Start()));
   6544 }
   6545 
   6546 void nsGlobalWindowInner::RequestXRPermission() {
   6547  if (IsDying()) {
   6548    // Do not proceed if the window is dying, as that will result
   6549    // in leaks of objects that get re-allocated after FreeInnerObjects
   6550    // has been called, including mVREventObserver.
   6551    return;
   6552  }
   6553  if (mXRPermissionGranted) {
   6554    // Don't prompt redundantly once permission to
   6555    // access XR devices has been granted.
   6556    OnXRPermissionRequestAllow();
   6557    return;
   6558  }
   6559  if (mXRRuntimeDetectionInFlight || mXRPermissionRequestInFlight) {
   6560    // Don't allow multiple simultaneous permissions requests;
   6561    return;
   6562  }
   6563  // Before displaying a permission prompt, detect
   6564  // if there is any VR runtime installed.
   6565  gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
   6566  mXRRuntimeDetectionInFlight = true;
   6567  EnableVRUpdates();
   6568  vm->DetectRuntimes();
   6569 }
   6570 
   6571 void nsGlobalWindowInner::OnXRPermissionRequestAllow() {
   6572  mXRPermissionRequestInFlight = false;
   6573  if (IsDying()) {
   6574    // The window may have started dying while the permission request
   6575    // is in flight.
   6576    // Do not proceed if the window is dying, as that will result
   6577    // in leaks of objects that get re-allocated after FreeInnerObjects
   6578    // has been called, including mNavigator.
   6579    return;
   6580  }
   6581  mXRPermissionGranted = true;
   6582 
   6583  NotifyHasXRSession();
   6584 
   6585  dom::Navigator* nav = Navigator();
   6586  MOZ_ASSERT(nav != nullptr);
   6587  nav->OnXRPermissionRequestAllow();
   6588 }
   6589 
   6590 void nsGlobalWindowInner::OnXRPermissionRequestCancel() {
   6591  mXRPermissionRequestInFlight = false;
   6592  if (IsDying()) {
   6593    // The window may have started dying while the permission request
   6594    // is in flight.
   6595    // Do not proceed if the window is dying, as that will result
   6596    // in leaks of objects that get re-allocated after FreeInnerObjects
   6597    // has been called, including mNavigator.
   6598    return;
   6599  }
   6600  dom::Navigator* nav = Navigator();
   6601  MOZ_ASSERT(nav != nullptr);
   6602  nav->OnXRPermissionRequestCancel();
   6603 }
   6604 
   6605 void nsGlobalWindowInner::EventListenerAdded(nsAtom* aType) {
   6606  if (aType == nsGkAtoms::onvrdisplayactivate ||
   6607      aType == nsGkAtoms::onvrdisplayconnect ||
   6608      aType == nsGkAtoms::onvrdisplaydeactivate ||
   6609      aType == nsGkAtoms::onvrdisplaydisconnect ||
   6610      aType == nsGkAtoms::onvrdisplaypresentchange) {
   6611    RequestXRPermission();
   6612  }
   6613 
   6614  if (aType == nsGkAtoms::onvrdisplayactivate) {
   6615    mHasVRDisplayActivateEvents = true;
   6616  }
   6617 
   6618  if (aType == nsGkAtoms::onunload && mWindowGlobalChild) {
   6619    if (++mUnloadOrBeforeUnloadListenerCount == 1) {
   6620      mWindowGlobalChild->BlockBFCacheFor(BFCacheStatus::UNLOAD_LISTENER);
   6621    }
   6622  }
   6623 
   6624  if (aType == nsGkAtoms::onbeforeunload && mWindowGlobalChild) {
   6625    if (!mozilla::SessionHistoryInParent() ||
   6626        !StaticPrefs::
   6627            docshell_shistory_bfcache_ship_allow_beforeunload_listeners()) {
   6628      if (++mUnloadOrBeforeUnloadListenerCount == 1) {
   6629        mWindowGlobalChild->BlockBFCacheFor(
   6630            BFCacheStatus::BEFOREUNLOAD_LISTENER);
   6631      }
   6632    }
   6633    if (!mDoc || !(mDoc->GetSandboxFlags() & SANDBOXED_MODALS)) {
   6634      mWindowGlobalChild->BeforeUnloadAdded();
   6635      MOZ_ASSERT(mWindowGlobalChild->BeforeUnloadListeners() > 0);
   6636    }
   6637  }
   6638 
   6639  // We need to initialize localStorage in order to receive notifications.
   6640  if (aType == nsGkAtoms::onstorage) {
   6641    ErrorResult rv;
   6642    GetLocalStorage(rv);
   6643    rv.SuppressException();
   6644 
   6645    if (NextGenLocalStorageEnabled() && mLocalStorage &&
   6646        mLocalStorage->Type() == Storage::eLocalStorage) {
   6647      auto object = static_cast<LSObject*>(mLocalStorage.get());
   6648 
   6649      (void)NS_WARN_IF(NS_FAILED(object->EnsureObserver()));
   6650    }
   6651  }
   6652 }
   6653 
   6654 void nsGlobalWindowInner::EventListenerRemoved(nsAtom* aType) {
   6655  if (aType == nsGkAtoms::onunload && mWindowGlobalChild) {
   6656    MOZ_ASSERT(mUnloadOrBeforeUnloadListenerCount > 0);
   6657    if (--mUnloadOrBeforeUnloadListenerCount == 0) {
   6658      mWindowGlobalChild->UnblockBFCacheFor(BFCacheStatus::UNLOAD_LISTENER);
   6659    }
   6660  }
   6661 
   6662  if (aType == nsGkAtoms::onbeforeunload && mWindowGlobalChild) {
   6663    if (!mozilla::SessionHistoryInParent() ||
   6664        !StaticPrefs::
   6665            docshell_shistory_bfcache_ship_allow_beforeunload_listeners()) {
   6666      if (--mUnloadOrBeforeUnloadListenerCount == 0) {
   6667        mWindowGlobalChild->UnblockBFCacheFor(
   6668            BFCacheStatus::BEFOREUNLOAD_LISTENER);
   6669      }
   6670    }
   6671    if (!mDoc || !(mDoc->GetSandboxFlags() & SANDBOXED_MODALS)) {
   6672      mWindowGlobalChild->BeforeUnloadRemoved();
   6673      MOZ_ASSERT(mWindowGlobalChild->BeforeUnloadListeners() >= 0);
   6674    }
   6675  }
   6676 
   6677  if (aType == nsGkAtoms::onstorage) {
   6678    if (NextGenLocalStorageEnabled() && mLocalStorage &&
   6679        mLocalStorage->Type() == Storage::eLocalStorage &&
   6680        // The remove event is fired even if this isn't the last listener, so
   6681        // only remove if there are no other listeners left.
   6682        mListenerManager &&
   6683        !mListenerManager->HasListenersFor(nsGkAtoms::onstorage)) {
   6684      auto object = static_cast<LSObject*>(mLocalStorage.get());
   6685 
   6686      object->DropObserver();
   6687    }
   6688  }
   6689 }
   6690 
   6691 void nsGlobalWindowInner::NotifyHasXRSession() {
   6692  if (IsDying()) {
   6693    // Do not proceed if the window is dying, as that will result
   6694    // in leaks of objects that get re-allocated after FreeInnerObjects
   6695    // has been called, including mVREventObserver.
   6696    return;
   6697  }
   6698  if (mWindowGlobalChild && !mHasXRSession) {
   6699    mWindowGlobalChild->BlockBFCacheFor(BFCacheStatus::HAS_USED_VR);
   6700  }
   6701  mHasXRSession = true;
   6702  EnableVRUpdates();
   6703 }
   6704 
   6705 bool nsGlobalWindowInner::HasUsedVR() const {
   6706  // Returns true only if content has enumerated and activated
   6707  // XR devices.  Detection of XR runtimes without activation
   6708  // will not cause true to be returned.
   6709  return mHasXRSession;
   6710 }
   6711 
   6712 bool nsGlobalWindowInner::IsVRContentDetected() const {
   6713  // Returns true only if the content will respond to
   6714  // the VRDisplayActivate event.
   6715  return mHasVRDisplayActivateEvents;
   6716 }
   6717 
   6718 bool nsGlobalWindowInner::IsVRContentPresenting() const {
   6719  for (const auto& display : mVRDisplays) {
   6720    if (display->IsAnyPresenting(gfx::kVRGroupAll)) {
   6721      return true;
   6722    }
   6723  }
   6724  return false;
   6725 }
   6726 
   6727 void nsGlobalWindowInner::AddSizeOfIncludingThis(
   6728    nsWindowSizes& aWindowSizes) const {
   6729  aWindowSizes.mDOMSizes.mDOMOtherSize +=
   6730      aWindowSizes.mState.mMallocSizeOf(this);
   6731  aWindowSizes.mDOMSizes.mDOMOtherSize +=
   6732      nsIGlobalObject::ShallowSizeOfExcludingThis(
   6733          aWindowSizes.mState.mMallocSizeOf);
   6734 
   6735  EventListenerManager* elm = GetExistingListenerManager();
   6736  if (elm) {
   6737    aWindowSizes.mDOMSizes.mDOMOtherSize +=
   6738        elm->SizeOfIncludingThis(aWindowSizes.mState.mMallocSizeOf);
   6739    aWindowSizes.mDOMEventListenersCount += elm->ListenerCount();
   6740  }
   6741  if (mDoc) {
   6742    // Multiple global windows can share a document. So only measure the
   6743    // document if it (a) doesn't have a global window, or (b) it's the
   6744    // primary document for the window.
   6745    if (!mDoc->GetInnerWindow() || mDoc->GetInnerWindow() == this) {
   6746      mDoc->DocAddSizeOfIncludingThis(aWindowSizes);
   6747    }
   6748  }
   6749 
   6750  if (mNavigation) {
   6751    aWindowSizes.mDOMSizes.mDOMOtherSize +=
   6752        aWindowSizes.mState.mMallocSizeOf(mNavigation.get());
   6753  }
   6754  if (mNavigator) {
   6755    aWindowSizes.mDOMSizes.mDOMOtherSize +=
   6756        mNavigator->SizeOfIncludingThis(aWindowSizes.mState.mMallocSizeOf);
   6757  }
   6758 
   6759  ForEachGlobalTeardownObserver([&](GlobalTeardownObserver* et,
   6760                                    bool* aDoneOut) {
   6761    if (nsCOMPtr<nsISizeOfEventTarget> iSizeOf = do_QueryObject(et)) {
   6762      aWindowSizes.mDOMSizes.mDOMEventTargetsSize +=
   6763          iSizeOf->SizeOfEventTargetIncludingThis(
   6764              aWindowSizes.mState.mMallocSizeOf);
   6765    }
   6766    if (nsCOMPtr<DOMEventTargetHelper> helper = do_QueryObject(et)) {
   6767      if (EventListenerManager* elm = helper->GetExistingListenerManager()) {
   6768        aWindowSizes.mDOMEventListenersCount += elm->ListenerCount();
   6769      }
   6770    }
   6771    ++aWindowSizes.mDOMEventTargetsCount;
   6772  });
   6773 
   6774  if (mPerformance) {
   6775    aWindowSizes.mDOMSizes.mDOMPerformanceUserEntries =
   6776        mPerformance->SizeOfUserEntries(aWindowSizes.mState.mMallocSizeOf);
   6777    aWindowSizes.mDOMSizes.mDOMPerformanceResourceEntries =
   6778        mPerformance->SizeOfResourceEntries(aWindowSizes.mState.mMallocSizeOf);
   6779    aWindowSizes.mDOMSizes.mDOMPerformanceEventEntries =
   6780        mPerformance->SizeOfEventEntries(aWindowSizes.mState.mMallocSizeOf);
   6781  }
   6782 }
   6783 
   6784 void nsGlobalWindowInner::RegisterDataDocumentForMemoryReporting(
   6785    Document* aDocument) {
   6786  aDocument->SetAddedToMemoryReportAsDataDocument();
   6787  mDataDocumentsForMemoryReporting.AppendElement(aDocument);
   6788 }
   6789 
   6790 void nsGlobalWindowInner::UnregisterDataDocumentForMemoryReporting(
   6791    Document* aDocument) {
   6792  DebugOnly<bool> found =
   6793      mDataDocumentsForMemoryReporting.RemoveElement(aDocument);
   6794  MOZ_ASSERT(found);
   6795 }
   6796 
   6797 void nsGlobalWindowInner::CollectDOMSizesForDataDocuments(
   6798    nsWindowSizes& aSize) const {
   6799  for (Document* doc : mDataDocumentsForMemoryReporting) {
   6800    if (doc) {
   6801      doc->DocAddSizeOfIncludingThis(aSize);
   6802    }
   6803  }
   6804 }
   6805 
   6806 void nsGlobalWindowInner::AddGamepad(GamepadHandle aHandle, Gamepad* aGamepad) {
   6807  // Create the index we will present to content based on which indices are
   6808  // already taken, as required by the spec.
   6809  // https://w3c.github.io/gamepad/gamepad.html#widl-Gamepad-index
   6810  int index = 0;
   6811  while (mGamepadIndexSet.Contains(index)) {
   6812    ++index;
   6813  }
   6814  mGamepadIndexSet.Put(index);
   6815  aGamepad->SetIndex(index);
   6816  mGamepads.InsertOrUpdate(aHandle, RefPtr{aGamepad});
   6817 }
   6818 
   6819 void nsGlobalWindowInner::RemoveGamepad(GamepadHandle aHandle) {
   6820  RefPtr<Gamepad> gamepad;
   6821  if (!mGamepads.Get(aHandle, getter_AddRefs(gamepad))) {
   6822    return;
   6823  }
   6824  // Free up the index we were using so it can be reused
   6825  mGamepadIndexSet.Remove(gamepad->Index());
   6826  mGamepads.Remove(aHandle);
   6827 }
   6828 
   6829 void nsGlobalWindowInner::GetGamepads(nsTArray<RefPtr<Gamepad>>& aGamepads) {
   6830  aGamepads.Clear();
   6831 
   6832  // navigator.getGamepads() always returns an empty array when
   6833  // privacy.resistFingerprinting is true.
   6834  if (ShouldResistFingerprinting(RFPTarget::Gamepad)) {
   6835    return;
   6836  }
   6837 
   6838  // mGamepads.Count() may not be sufficient, but it's not harmful.
   6839  aGamepads.SetCapacity(mGamepads.Count());
   6840  for (const auto& entry : mGamepads) {
   6841    Gamepad* gamepad = entry.GetWeak();
   6842    aGamepads.EnsureLengthAtLeast(gamepad->Index() + 1);
   6843    aGamepads[gamepad->Index()] = gamepad;
   6844  }
   6845 }
   6846 
   6847 already_AddRefed<mozilla::dom::Promise> nsGlobalWindowInner::RequestAllGamepads(
   6848    ErrorResult& aRv) {
   6849  RefPtr<GamepadManager> gamepadManager(GamepadManager::GetService());
   6850 
   6851  if (!gamepadManager) {
   6852    aRv.Throw(NS_ERROR_UNEXPECTED);
   6853    return nullptr;
   6854  }
   6855 
   6856  return gamepadManager->RequestAllGamepads(this, aRv);
   6857 }
   6858 
   6859 already_AddRefed<Gamepad> nsGlobalWindowInner::GetGamepad(
   6860    GamepadHandle aHandle) {
   6861  RefPtr<Gamepad> gamepad;
   6862 
   6863  if (mGamepads.Get(aHandle, getter_AddRefs(gamepad))) {
   6864    return gamepad.forget();
   6865  }
   6866 
   6867  return nullptr;
   6868 }
   6869 
   6870 void nsGlobalWindowInner::SetHasSeenGamepadInput(bool aHasSeen) {
   6871  mHasSeenGamepadInput = aHasSeen;
   6872 }
   6873 
   6874 bool nsGlobalWindowInner::HasSeenGamepadInput() { return mHasSeenGamepadInput; }
   6875 
   6876 void nsGlobalWindowInner::SyncGamepadState() {
   6877  if (mHasSeenGamepadInput) {
   6878    RefPtr<GamepadManager> gamepadManager(GamepadManager::GetService());
   6879    for (const auto& entry : mGamepads) {
   6880      gamepadManager->SyncGamepadState(entry.GetKey(), this, entry.GetWeak());
   6881    }
   6882  }
   6883 }
   6884 
   6885 void nsGlobalWindowInner::StopGamepadHaptics() {
   6886  if (mHasSeenGamepadInput) {
   6887    RefPtr<GamepadManager> gamepadManager(GamepadManager::GetService());
   6888    gamepadManager->StopHaptics();
   6889  }
   6890 }
   6891 
   6892 bool nsGlobalWindowInner::UpdateVRDisplays(
   6893    nsTArray<RefPtr<mozilla::dom::VRDisplay>>& aDevices) {
   6894  VRDisplay::UpdateVRDisplays(mVRDisplays, this);
   6895  aDevices = mVRDisplays.Clone();
   6896  return true;
   6897 }
   6898 
   6899 void nsGlobalWindowInner::NotifyActiveVRDisplaysChanged() {
   6900  if (mNavigator) {
   6901    mNavigator->NotifyActiveVRDisplaysChanged();
   6902  }
   6903 }
   6904 
   6905 void nsGlobalWindowInner::NotifyPresentationGenerationChanged(
   6906    uint32_t aDisplayID) {
   6907  for (const auto& display : mVRDisplays) {
   6908    if (display->DisplayId() == aDisplayID) {
   6909      display->OnPresentationGenerationChanged();
   6910    }
   6911  }
   6912 }
   6913 
   6914 void nsGlobalWindowInner::DispatchVRDisplayActivate(
   6915    uint32_t aDisplayID, mozilla::dom::VRDisplayEventReason aReason) {
   6916  // Ensure that our list of displays is up to date
   6917  VRDisplay::UpdateVRDisplays(mVRDisplays, this);
   6918 
   6919  // Search for the display identified with aDisplayID and fire the
   6920  // event if found.
   6921  for (const auto& display : mVRDisplays) {
   6922    if (display->DisplayId() == aDisplayID) {
   6923      if (aReason != VRDisplayEventReason::Navigation &&
   6924          display->IsAnyPresenting(gfx::kVRGroupContent)) {
   6925        // We only want to trigger this event if nobody is presenting to the
   6926        // display already or when a page is loaded by navigating away
   6927        // from a page with an active VR Presentation.
   6928        continue;
   6929      }
   6930 
   6931      VRDisplayEventInit init;
   6932      init.mBubbles = false;
   6933      init.mCancelable = false;
   6934      init.mDisplay = display;
   6935      init.mReason.Construct(aReason);
   6936 
   6937      RefPtr<VRDisplayEvent> event =
   6938          VRDisplayEvent::Constructor(this, u"vrdisplayactivate"_ns, init);
   6939      // vrdisplayactivate is a trusted event, allowing VRDisplay.requestPresent
   6940      // to be used in response to link traversal, user request (chrome UX), and
   6941      // HMD mounting detection sensors.
   6942      event->SetTrusted(true);
   6943      // VRDisplay.requestPresent normally requires a user gesture; however, an
   6944      // exception is made to allow it to be called in response to
   6945      // vrdisplayactivate during VR link traversal.
   6946      display->StartHandlingVRNavigationEvent();
   6947      DispatchEvent(*event);
   6948      display->StopHandlingVRNavigationEvent();
   6949      // Once we dispatch the event, we must not access any members as an event
   6950      // listener can do anything, including closing windows.
   6951      return;
   6952    }
   6953  }
   6954 }
   6955 
   6956 void nsGlobalWindowInner::DispatchVRDisplayDeactivate(
   6957    uint32_t aDisplayID, mozilla::dom::VRDisplayEventReason aReason) {
   6958  // Ensure that our list of displays is up to date
   6959  VRDisplay::UpdateVRDisplays(mVRDisplays, this);
   6960 
   6961  // Search for the display identified with aDisplayID and fire the
   6962  // event if found.
   6963  for (const auto& display : mVRDisplays) {
   6964    if (display->DisplayId() == aDisplayID && display->IsPresenting()) {
   6965      // We only want to trigger this event to content that is presenting to
   6966      // the display already.
   6967 
   6968      VRDisplayEventInit init;
   6969      init.mBubbles = false;
   6970      init.mCancelable = false;
   6971      init.mDisplay = display;
   6972      init.mReason.Construct(aReason);
   6973 
   6974      RefPtr<VRDisplayEvent> event =
   6975          VRDisplayEvent::Constructor(this, u"vrdisplaydeactivate"_ns, init);
   6976      event->SetTrusted(true);
   6977      DispatchEvent(*event);
   6978      // Once we dispatch the event, we must not access any members as an event
   6979      // listener can do anything, including closing windows.
   6980      return;
   6981    }
   6982  }
   6983 }
   6984 
   6985 void nsGlobalWindowInner::DispatchVRDisplayConnect(uint32_t aDisplayID) {
   6986  // Ensure that our list of displays is up to date
   6987  VRDisplay::UpdateVRDisplays(mVRDisplays, this);
   6988 
   6989  // Search for the display identified with aDisplayID and fire the
   6990  // event if found.
   6991  for (const auto& display : mVRDisplays) {
   6992    if (display->DisplayId() == aDisplayID) {
   6993      // Fire event even if not presenting to the display.
   6994      VRDisplayEventInit init;
   6995      init.mBubbles = false;
   6996      init.mCancelable = false;
   6997      init.mDisplay = display;
   6998      // VRDisplayEvent.reason is not set for vrdisplayconnect
   6999 
   7000      RefPtr<VRDisplayEvent> event =
   7001          VRDisplayEvent::Constructor(this, u"vrdisplayconnect"_ns, init);
   7002      event->SetTrusted(true);
   7003      DispatchEvent(*event);
   7004      // Once we dispatch the event, we must not access any members as an event
   7005      // listener can do anything, including closing windows.
   7006      return;
   7007    }
   7008  }
   7009 }
   7010 
   7011 void nsGlobalWindowInner::DispatchVRDisplayDisconnect(uint32_t aDisplayID) {
   7012  // Ensure that our list of displays is up to date
   7013  VRDisplay::UpdateVRDisplays(mVRDisplays, this);
   7014 
   7015  // Search for the display identified with aDisplayID and fire the
   7016  // event if found.
   7017  for (const auto& display : mVRDisplays) {
   7018    if (display->DisplayId() == aDisplayID) {
   7019      // Fire event even if not presenting to the display.
   7020      VRDisplayEventInit init;
   7021      init.mBubbles = false;
   7022      init.mCancelable = false;
   7023      init.mDisplay = display;
   7024      // VRDisplayEvent.reason is not set for vrdisplaydisconnect
   7025 
   7026      RefPtr<VRDisplayEvent> event =
   7027          VRDisplayEvent::Constructor(this, u"vrdisplaydisconnect"_ns, init);
   7028      event->SetTrusted(true);
   7029      DispatchEvent(*event);
   7030      // Once we dispatch the event, we must not access any members as an event
   7031      // listener can do anything, including closing windows.
   7032      return;
   7033    }
   7034  }
   7035 }
   7036 
   7037 void nsGlobalWindowInner::DispatchVRDisplayPresentChange(uint32_t aDisplayID) {
   7038  // Ensure that our list of displays is up to date
   7039  VRDisplay::UpdateVRDisplays(mVRDisplays, this);
   7040 
   7041  // Search for the display identified with aDisplayID and fire the
   7042  // event if found.
   7043  for (const auto& display : mVRDisplays) {
   7044    if (display->DisplayId() == aDisplayID) {
   7045      // Fire event even if not presenting to the display.
   7046      VRDisplayEventInit init;
   7047      init.mBubbles = false;
   7048      init.mCancelable = false;
   7049      init.mDisplay = display;
   7050      // VRDisplayEvent.reason is not set for vrdisplaypresentchange
   7051      RefPtr<VRDisplayEvent> event =
   7052          VRDisplayEvent::Constructor(this, u"vrdisplaypresentchange"_ns, init);
   7053      event->SetTrusted(true);
   7054      DispatchEvent(*event);
   7055      // Once we dispatch the event, we must not access any members as an event
   7056      // listener can do anything, including closing windows.
   7057      return;
   7058    }
   7059  }
   7060 }
   7061 
   7062 enum WindowState {
   7063  // These constants need to match the constants in Window.webidl
   7064  STATE_MAXIMIZED = 1,
   7065  STATE_MINIMIZED = 2,
   7066  STATE_NORMAL = 3,
   7067  STATE_FULLSCREEN = 4
   7068 };
   7069 
   7070 uint16_t nsGlobalWindowInner::WindowState() {
   7071  nsCOMPtr<nsIWidget> widget = GetMainWidget();
   7072 
   7073  int32_t mode = widget ? widget->SizeMode() : 0;
   7074 
   7075  switch (mode) {
   7076    case nsSizeMode_Minimized:
   7077      return STATE_MINIMIZED;
   7078    case nsSizeMode_Maximized:
   7079      return STATE_MAXIMIZED;
   7080    case nsSizeMode_Fullscreen:
   7081      return STATE_FULLSCREEN;
   7082    case nsSizeMode_Normal:
   7083      return STATE_NORMAL;
   7084    default:
   7085      NS_WARNING("Illegal window state for this chrome window");
   7086      break;
   7087  }
   7088 
   7089  return STATE_NORMAL;
   7090 }
   7091 
   7092 bool nsGlobalWindowInner::IsFullyOccluded() {
   7093  nsCOMPtr<nsIWidget> widget = GetMainWidget();
   7094  return widget && widget->IsFullyOccluded();
   7095 }
   7096 
   7097 void nsGlobalWindowInner::Maximize() {
   7098  if (nsCOMPtr<nsIWidget> widget = GetMainWidget()) {
   7099    widget->SetSizeMode(nsSizeMode_Maximized);
   7100  }
   7101 }
   7102 
   7103 void nsGlobalWindowInner::Minimize() {
   7104  if (nsCOMPtr<nsIWidget> widget = GetMainWidget()) {
   7105    widget->SetSizeMode(nsSizeMode_Minimized);
   7106  }
   7107 }
   7108 
   7109 void nsGlobalWindowInner::Restore() {
   7110  if (nsCOMPtr<nsIWidget> widget = GetMainWidget()) {
   7111    widget->SetSizeMode(nsSizeMode_Normal);
   7112  }
   7113 }
   7114 
   7115 void nsGlobalWindowInner::GetWorkspaceID(nsAString& workspaceID) {
   7116  workspaceID.Truncate();
   7117  if (nsCOMPtr<nsIWidget> widget = GetMainWidget()) {
   7118    return widget->GetWorkspaceID(workspaceID);
   7119  }
   7120 }
   7121 
   7122 void nsGlobalWindowInner::MoveToWorkspace(const nsAString& workspaceID) {
   7123  if (nsCOMPtr<nsIWidget> widget = GetMainWidget()) {
   7124    widget->MoveToWorkspace(workspaceID);
   7125  }
   7126 }
   7127 
   7128 bool nsGlobalWindowInner::IsCloaked() const {
   7129  if (nsCOMPtr<nsIWidget> widget = GetMainWidget()) {
   7130    return widget->IsCloaked();
   7131  }
   7132  // Assume that it is not, since most windows are not cloaked.
   7133  return false;
   7134 }
   7135 
   7136 void nsGlobalWindowInner::GetAttention(ErrorResult& aResult) {
   7137  return GetAttentionWithCycleCount(-1, aResult);
   7138 }
   7139 
   7140 void nsGlobalWindowInner::GetAttentionWithCycleCount(int32_t aCycleCount,
   7141                                                     ErrorResult& aError) {
   7142  nsCOMPtr<nsIWidget> widget = GetMainWidget();
   7143 
   7144  if (widget) {
   7145    aError = widget->GetAttention(aCycleCount);
   7146  }
   7147 }
   7148 
   7149 already_AddRefed<Promise> nsGlobalWindowInner::PromiseDocumentFlushed(
   7150    PromiseDocumentFlushedCallback& aCallback, ErrorResult& aError) {
   7151  MOZ_RELEASE_ASSERT(IsChromeWindow());
   7152 
   7153  if (!IsCurrentInnerWindow()) {
   7154    aError.ThrowInvalidStateError("Not the current inner window");
   7155    return nullptr;
   7156  }
   7157  if (!mDoc) {
   7158    aError.ThrowInvalidStateError("No document");
   7159    return nullptr;
   7160  }
   7161 
   7162  if (mIteratingDocumentFlushedResolvers) {
   7163    aError.ThrowInvalidStateError("Already iterating through resolvers");
   7164    return nullptr;
   7165  }
   7166 
   7167  PresShell* presShell = mDoc->GetPresShell();
   7168  if (!presShell) {
   7169    aError.ThrowInvalidStateError("No pres shell");
   7170    return nullptr;
   7171  }
   7172 
   7173  // We need to associate the lifetime of the Promise to the lifetime
   7174  // of the caller's global. That way, if the window we're observing
   7175  // refresh driver ticks on goes away before our observer is fired,
   7176  // we can still resolve the Promise.
   7177  nsIGlobalObject* global = GetIncumbentGlobal();
   7178  if (!global) {
   7179    aError.ThrowInvalidStateError("No incumbent global");
   7180    return nullptr;
   7181  }
   7182 
   7183  RefPtr<Promise> resultPromise = Promise::Create(global, aError);
   7184  if (aError.Failed()) {
   7185    return nullptr;
   7186  }
   7187 
   7188  UniquePtr<PromiseDocumentFlushedResolver> flushResolver(
   7189      new PromiseDocumentFlushedResolver(resultPromise, aCallback));
   7190 
   7191  if (!presShell->NeedStyleFlush() && !presShell->NeedLayoutFlush()) {
   7192    flushResolver->Call();
   7193    return resultPromise.forget();
   7194  }
   7195 
   7196  if (!TryToObserveRefresh()) {
   7197    aError.ThrowInvalidStateError("Couldn't observe refresh");
   7198    return nullptr;
   7199  }
   7200 
   7201  mDocumentFlushedResolvers.AppendElement(std::move(flushResolver));
   7202  return resultPromise.forget();
   7203 }
   7204 
   7205 bool nsGlobalWindowInner::TryToObserveRefresh() {
   7206  if (mObservingRefresh) {
   7207    return true;
   7208  }
   7209 
   7210  if (!mDoc) {
   7211    return false;
   7212  }
   7213 
   7214  nsPresContext* pc = mDoc->GetPresContext();
   7215  if (!pc) {
   7216    return false;
   7217  }
   7218 
   7219  mObservingRefresh = true;
   7220  auto observer = MakeRefPtr<ManagedPostRefreshObserver>(
   7221      pc, [win = RefPtr{this}](bool aWasCanceled) {
   7222        if (win->MaybeCallDocumentFlushedResolvers(
   7223                /* aUntilExhaustion = */ aWasCanceled)) {
   7224          return ManagedPostRefreshObserver::Unregister::No;
   7225        }
   7226        win->mObservingRefresh = false;
   7227        return ManagedPostRefreshObserver::Unregister::Yes;
   7228      });
   7229  pc->RegisterManagedPostRefreshObserver(observer.get());
   7230  return mObservingRefresh;
   7231 }
   7232 
   7233 void nsGlobalWindowInner::CallDocumentFlushedResolvers(bool aUntilExhaustion) {
   7234  while (true) {
   7235    {
   7236      // To coalesce MicroTask checkpoints inside callback call, enclose the
   7237      // inner loop with nsAutoMicroTask, and perform a MicroTask checkpoint
   7238      // after the loop.
   7239      nsAutoMicroTask mt;
   7240 
   7241      mIteratingDocumentFlushedResolvers = true;
   7242 
   7243      auto resolvers = std::move(mDocumentFlushedResolvers);
   7244      for (const auto& resolver : resolvers) {
   7245        resolver->Call();
   7246      }
   7247 
   7248      mIteratingDocumentFlushedResolvers = false;
   7249    }
   7250 
   7251    // Leaving nsAutoMicroTask above will perform MicroTask checkpoint, and
   7252    // Promise callbacks there may create mDocumentFlushedResolvers items.
   7253 
   7254    // If there's no new resolvers, or we're not exhausting the queue, there's
   7255    // nothing to do (we'll keep observing if there's any new observer).
   7256    //
   7257    // Otherwise, keep looping to call all promises. This case can happen while
   7258    // destroying the window.  This violates the constraint that the
   7259    // promiseDocumentFlushed callback only ever run when no flush is needed,
   7260    // but it's necessary to resolve the Promise returned by that.
   7261    if (!aUntilExhaustion || mDocumentFlushedResolvers.IsEmpty()) {
   7262      break;
   7263    }
   7264  }
   7265 }
   7266 
   7267 bool nsGlobalWindowInner::MaybeCallDocumentFlushedResolvers(
   7268    bool aUntilExhaustion) {
   7269  MOZ_ASSERT(mDoc);
   7270 
   7271  PresShell* presShell = mDoc->GetPresShell();
   7272  if (!presShell || aUntilExhaustion) {
   7273    CallDocumentFlushedResolvers(/* aUntilExhaustion = */ true);
   7274    return false;
   7275  }
   7276 
   7277  if (presShell->NeedStyleFlush() || presShell->NeedLayoutFlush()) {
   7278    // By the time our observer fired, something has already invalidated
   7279    // style or layout - or perhaps we're still in the middle of a flush that
   7280    // was interrupted. In either case, we'll wait until the next refresh driver
   7281    // tick instead and try again.
   7282    return true;
   7283  }
   7284 
   7285  CallDocumentFlushedResolvers(/* aUntilExhaustion = */ false);
   7286  return !mDocumentFlushedResolvers.IsEmpty();
   7287 }
   7288 
   7289 already_AddRefed<nsWindowRoot> nsGlobalWindowInner::GetWindowRoot(
   7290    mozilla::ErrorResult& aError) {
   7291  FORWARD_TO_OUTER_OR_THROW(GetWindowRootOuter, (), aError, nullptr);
   7292 }
   7293 
   7294 void nsGlobalWindowInner::SetCursor(const nsACString& aCursor,
   7295                                    ErrorResult& aError) {
   7296  FORWARD_TO_OUTER_OR_THROW(SetCursorOuter, (aCursor, aError), aError, );
   7297 }
   7298 
   7299 nsIBrowserDOMWindow* nsGlobalWindowInner::GetBrowserDOMWindow(
   7300    ErrorResult& aError) {
   7301  FORWARD_TO_OUTER_OR_THROW(GetBrowserDOMWindow, (), aError, nullptr);
   7302 }
   7303 
   7304 void nsGlobalWindowInner::SetBrowserDOMWindow(
   7305    nsIBrowserDOMWindow* aBrowserWindow, ErrorResult& aError) {
   7306  FORWARD_TO_OUTER_OR_THROW(SetBrowserDOMWindowOuter, (aBrowserWindow),
   7307                            aError, );
   7308 }
   7309 
   7310 void nsGlobalWindowInner::NotifyDefaultButtonLoaded(Element& aDefaultButton,
   7311                                                    ErrorResult& aError) {
   7312  // Don't snap to a disabled button.
   7313  nsCOMPtr<nsIDOMXULControlElement> xulControl = aDefaultButton.AsXULControl();
   7314  if (!xulControl) {
   7315    aError.Throw(NS_ERROR_FAILURE);
   7316    return;
   7317  }
   7318  bool disabled;
   7319  aError = xulControl->GetDisabled(&disabled);
   7320  if (aError.Failed() || disabled) {
   7321    return;
   7322  }
   7323 
   7324  // Get the button rect in screen coordinates.
   7325  nsIFrame* frame = aDefaultButton.GetPrimaryFrame();
   7326  if (!frame) {
   7327    aError.Throw(NS_ERROR_FAILURE);
   7328    return;
   7329  }
   7330  LayoutDeviceIntRect buttonRect = LayoutDeviceIntRect::FromAppUnitsToNearest(
   7331      frame->GetScreenRectInAppUnits(),
   7332      frame->PresContext()->AppUnitsPerDevPixel());
   7333 
   7334  // Get the widget rect in screen coordinates.
   7335  nsIWidget* widget = GetNearestWidget();
   7336  if (!widget) {
   7337    aError.Throw(NS_ERROR_FAILURE);
   7338    return;
   7339  }
   7340  LayoutDeviceIntRect widgetRect = widget->GetScreenBounds();
   7341 
   7342  // Convert the buttonRect coordinates from screen to the widget.
   7343  buttonRect -= widgetRect.TopLeft();
   7344  nsresult rv = widget->OnDefaultButtonLoaded(buttonRect);
   7345  if (NS_FAILED(rv) && rv != NS_ERROR_NOT_IMPLEMENTED) {
   7346    aError.Throw(rv);
   7347  }
   7348 }
   7349 
   7350 ChromeMessageBroadcaster* nsGlobalWindowInner::MessageManager() {
   7351  MOZ_ASSERT(IsChromeWindow());
   7352  if (!mChromeFields.mMessageManager) {
   7353    RefPtr<ChromeMessageBroadcaster> globalMM =
   7354        nsFrameMessageManager::GetGlobalMessageManager();
   7355    mChromeFields.mMessageManager = new ChromeMessageBroadcaster(globalMM);
   7356  }
   7357  return mChromeFields.mMessageManager;
   7358 }
   7359 
   7360 ChromeMessageBroadcaster* nsGlobalWindowInner::GetGroupMessageManager(
   7361    const nsAString& aGroup) {
   7362  MOZ_ASSERT(IsChromeWindow());
   7363 
   7364  return mChromeFields.mGroupMessageManagers
   7365      .LookupOrInsertWith(
   7366          aGroup,
   7367          [&] {
   7368            return MakeAndAddRef<ChromeMessageBroadcaster>(MessageManager());
   7369          })
   7370      .get();
   7371 }
   7372 
   7373 void nsGlobalWindowInner::InitWasOffline() { mWasOffline = NS_IsOffline(); }
   7374 
   7375 int16_t nsGlobalWindowInner::Orientation(CallerType aCallerType) {
   7376  // GetOrientationAngle() returns 0, 90, 180 or 270.
   7377  // window.orientation returns -90, 0, 90 or 180.
   7378  uint16_t screenAngle = Screen()->GetOrientationAngle();
   7379  if (nsIGlobalObject::ShouldResistFingerprinting(
   7380          aCallerType, RFPTarget::ScreenOrientation)) {
   7381    CSSIntSize size = mBrowsingContext->GetTopInnerSizeForRFP();
   7382    screenAngle = nsRFPService::ViewportSizeToAngle(size.width, size.height);
   7383  }
   7384  int16_t angle = AssertedCast<int16_t>(screenAngle);
   7385  return angle <= 180 ? angle : angle - 360;
   7386 }
   7387 
   7388 already_AddRefed<Console> nsGlobalWindowInner::GetConsole(JSContext* aCx,
   7389                                                          ErrorResult& aRv) {
   7390  if (!mConsole) {
   7391    mConsole = Console::Create(aCx, this, aRv);
   7392    if (NS_WARN_IF(aRv.Failed())) {
   7393      return nullptr;
   7394    }
   7395  }
   7396 
   7397  RefPtr<Console> console = mConsole;
   7398  return console.forget();
   7399 }
   7400 
   7401 already_AddRefed<CookieStore> nsGlobalWindowInner::CookieStore() {
   7402  if (!mCookieStore) {
   7403    mCookieStore = CookieStore::Create(this);
   7404  }
   7405 
   7406  return do_AddRef(mCookieStore);
   7407 }
   7408 
   7409 DocumentPictureInPicture* nsGlobalWindowInner::DocumentPictureInPicture() {
   7410  if (!mDocumentPiP) {
   7411    mDocumentPiP = MakeRefPtr<class DocumentPictureInPicture>(this);
   7412  }
   7413 
   7414  return mDocumentPiP;
   7415 }
   7416 
   7417 bool nsGlobalWindowInner::IsSecureContext() const {
   7418  JS::Realm* realm = js::GetNonCCWObjectRealm(GetWrapperPreserveColor());
   7419  return JS::GetIsSecureContext(realm);
   7420 }
   7421 
   7422 External* nsGlobalWindowInner::External() {
   7423  if (!mExternal) {
   7424    mExternal = new dom::External(ToSupports(this));
   7425  }
   7426 
   7427  return mExternal;
   7428 }
   7429 
   7430 void nsGlobalWindowInner::ClearDocumentDependentSlots(JSContext* aCx) {
   7431  // If JSAPI OOMs here, there is basically nothing we can do to recover safely.
   7432  if (!Window_Binding::ClearCachedDocumentValue(aCx, this) ||
   7433      !Window_Binding::ClearCachedPerformanceValue(aCx, this)) {
   7434    MOZ_CRASH("Unhandlable OOM while clearing document dependent slots.");
   7435  }
   7436 }
   7437 
   7438 /* static */
   7439 JSObject* nsGlobalWindowInner::CreateNamedPropertiesObject(
   7440    JSContext* aCx, JS::Handle<JSObject*> aProto) {
   7441  return WindowNamedPropertiesHandler::Create(aCx, aProto);
   7442 }
   7443 
   7444 void nsGlobalWindowInner::RedefineProperty(JSContext* aCx,
   7445                                           const char* aPropName,
   7446                                           JS::Handle<JS::Value> aValue,
   7447                                           ErrorResult& aError) {
   7448  JS::Rooted<JSObject*> thisObj(aCx, GetWrapperPreserveColor());
   7449  if (!thisObj) {
   7450    aError.Throw(NS_ERROR_UNEXPECTED);
   7451    return;
   7452  }
   7453 
   7454  if (!JS_WrapObject(aCx, &thisObj) ||
   7455      !JS_DefineProperty(aCx, thisObj, aPropName, aValue, JSPROP_ENUMERATE)) {
   7456    aError.Throw(NS_ERROR_FAILURE);
   7457  }
   7458 }
   7459 
   7460 void nsGlobalWindowInner::FireOnNewGlobalObject() {
   7461  // AutoEntryScript required to invoke debugger hook, which is a
   7462  // Gecko-specific concept at present.
   7463  AutoEntryScript aes(this, "nsGlobalWindowInner report new global");
   7464  JS::Rooted<JSObject*> global(aes.cx(), GetWrapper());
   7465  JS_FireOnNewGlobalObject(aes.cx(), global);
   7466 }
   7467 
   7468 #if defined(_WINDOWS_) && !defined(MOZ_WRAPPED_WINDOWS_H)
   7469 #  pragma message( \
   7470      "wrapper failure reason: " MOZ_WINDOWS_WRAPPER_DISABLED_REASON)
   7471 #  error "Never include unwrapped windows.h in this file!"
   7472 #endif
   7473 
   7474 already_AddRefed<Promise> nsGlobalWindowInner::CreateImageBitmap(
   7475    const ImageBitmapSource& aImage, const ImageBitmapOptions& aOptions,
   7476    ErrorResult& aRv) {
   7477  return ImageBitmap::Create(this, aImage, Nothing(), aOptions, aRv);
   7478 }
   7479 
   7480 already_AddRefed<Promise> nsGlobalWindowInner::CreateImageBitmap(
   7481    const ImageBitmapSource& aImage, int32_t aSx, int32_t aSy, int32_t aSw,
   7482    int32_t aSh, const ImageBitmapOptions& aOptions, ErrorResult& aRv) {
   7483  return ImageBitmap::Create(
   7484      this, aImage, Some(gfx::IntRect(aSx, aSy, aSw, aSh)), aOptions, aRv);
   7485 }
   7486 
   7487 // https://html.spec.whatwg.org/#structured-cloning
   7488 void nsGlobalWindowInner::StructuredClone(
   7489    JSContext* aCx, JS::Handle<JS::Value> aValue,
   7490    const StructuredSerializeOptions& aOptions,
   7491    JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError) {
   7492  nsContentUtils::StructuredClone(aCx, this, aValue, aOptions, aRetval, aError);
   7493 }
   7494 
   7495 nsresult nsGlobalWindowInner::Dispatch(
   7496    already_AddRefed<nsIRunnable>&& aRunnable) const {
   7497  MOZ_RELEASE_ASSERT(NS_IsMainThread());
   7498  return NS_DispatchToCurrentThread(std::move(aRunnable));
   7499 }
   7500 
   7501 nsISerialEventTarget* nsGlobalWindowInner::SerialEventTarget() const {
   7502  MOZ_RELEASE_ASSERT(NS_IsMainThread());
   7503  return GetMainThreadSerialEventTarget();
   7504 }
   7505 
   7506 Worklet* nsGlobalWindowInner::GetPaintWorklet(ErrorResult& aRv) {
   7507  if (!mPaintWorklet) {
   7508    nsIPrincipal* principal = GetPrincipal();
   7509    if (!principal) {
   7510      aRv.Throw(NS_ERROR_FAILURE);
   7511      return nullptr;
   7512    }
   7513 
   7514    mPaintWorklet = PaintWorkletImpl::CreateWorklet(this, principal);
   7515  }
   7516 
   7517  return mPaintWorklet;
   7518 }
   7519 
   7520 void nsGlobalWindowInner::GetWebExposedLocales(nsTArray<nsString>& aLocales) {
   7521  MOZ_ASSERT(mozilla::intl::LocaleService::GetInstance());
   7522 
   7523  AutoTArray<nsCString, 10> rpLocales;
   7524  mozilla::intl::LocaleService::GetInstance()->GetWebExposedLocales(rpLocales);
   7525 
   7526  for (const auto& loc : rpLocales) {
   7527    aLocales.AppendElement(NS_ConvertUTF8toUTF16(loc));
   7528  }
   7529 }
   7530 
   7531 IntlUtils* nsGlobalWindowInner::GetIntlUtils(ErrorResult& aError) {
   7532  if (!mIntlUtils) {
   7533    mIntlUtils = new IntlUtils(this);
   7534  }
   7535 
   7536  return mIntlUtils;
   7537 }
   7538 
   7539 void nsGlobalWindowInner::StoreSharedWorker(SharedWorker* aSharedWorker) {
   7540  MOZ_ASSERT(aSharedWorker);
   7541  MOZ_ASSERT(!mSharedWorkers.Contains(aSharedWorker));
   7542 
   7543  mSharedWorkers.AppendElement(aSharedWorker);
   7544 }
   7545 
   7546 void nsGlobalWindowInner::ForgetSharedWorker(SharedWorker* aSharedWorker) {
   7547  MOZ_ASSERT(aSharedWorker);
   7548  MOZ_ASSERT(mSharedWorkers.Contains(aSharedWorker));
   7549 
   7550  mSharedWorkers.RemoveElement(aSharedWorker);
   7551 }
   7552 
   7553 RefPtr<GenericPromise> nsGlobalWindowInner::StorageAccessPermissionChanged(
   7554    bool aGranted) {
   7555  // Invalidate cached StorageAllowed field so that calls to GetLocalStorage
   7556  // give us the updated localStorage object.
   7557  ClearStorageAllowedCache();
   7558 
   7559  // If we're always partitioning non-cookie third party storage then
   7560  // there is no need to clear it when the user accepts requestStorageAccess.
   7561  if (StaticPrefs::
   7562          privacy_partition_always_partition_third_party_non_cookie_storage()) {
   7563    // Just reset the active cookie and storage principals
   7564    nsCOMPtr<nsICookieJarSettings> cjs;
   7565    if (mDoc) {
   7566      cjs = mDoc->CookieJarSettings();
   7567    }
   7568    StorageAccess storageAccess = StorageAllowedForWindow(this);
   7569    if (ShouldPartitionStorage(storageAccess) &&
   7570        StoragePartitioningEnabled(storageAccess, cjs)) {
   7571      if (mDoc) {
   7572        mDoc->ClearActiveCookieAndStoragePrincipals();
   7573      }
   7574      // When storage access is granted the content process needs to request the
   7575      // updated cookie list from the parent process. Otherwise the site won't
   7576      // have access to unpartitioned cookies via document.cookie without a
   7577      // reload.
   7578      if (aGranted) {
   7579        nsIChannel* channel = mDoc->GetChannel();
   7580        if (channel) {
   7581          // The promise resolves when the updated cookie list has been received
   7582          // from the parent.
   7583          return ContentChild::UpdateCookieStatus(channel);
   7584        }
   7585      }
   7586    }
   7587  }
   7588 
   7589  PropagateStorageAccessPermissionGrantedToWorkers(*this);
   7590 
   7591  // If we have a partitioned localStorage, it's time to replace it with a real
   7592  // one in order to receive notifications.
   7593 
   7594  if (mLocalStorage) {
   7595    IgnoredErrorResult error;
   7596    GetLocalStorage(error);
   7597    if (NS_WARN_IF(error.Failed())) {
   7598      return MozPromise<bool, nsresult, true>::CreateAndReject(
   7599          error.StealNSResult(), __func__);
   7600    }
   7601 
   7602    MOZ_ASSERT(mLocalStorage &&
   7603               mLocalStorage->Type() == Storage::eLocalStorage);
   7604 
   7605    if (NextGenLocalStorageEnabled() && mListenerManager &&
   7606        mListenerManager->HasListenersFor(nsGkAtoms::onstorage)) {
   7607      auto object = static_cast<LSObject*>(mLocalStorage.get());
   7608 
   7609      object->EnsureObserver();
   7610    }
   7611  }
   7612 
   7613  // Reset the IndexedDB factory.
   7614  mIndexedDB = nullptr;
   7615 
   7616  // Reset DOM Cache
   7617  mCacheStorage = nullptr;
   7618 
   7619  // Reset the active cookie and storage principals
   7620  if (mDoc) {
   7621    mDoc->ClearActiveCookieAndStoragePrincipals();
   7622    if (mWindowGlobalChild) {
   7623      // XXX(farre): This is a bit backwards, but clearing the cookie
   7624      // principal might make us end up with a new effective storage
   7625      // principal on the child side than on the parent side, which
   7626      // means that we need to sync it. See bug 1705359.
   7627      mWindowGlobalChild->SetDocumentPrincipal(
   7628          mDoc->NodePrincipal(), mDoc->EffectiveStoragePrincipal());
   7629    }
   7630  }
   7631 
   7632  // When storage access is granted the content process needs to request the
   7633  // updated cookie list from the parent process. Otherwise the site won't have
   7634  // access to unpartitioned cookies via document.cookie without a reload.
   7635  if (aGranted) {
   7636    nsIChannel* channel = mDoc->GetChannel();
   7637    if (channel) {
   7638      // The promise resolves when the updated cookie list has been received
   7639      // from the parent.
   7640      return ContentChild::UpdateCookieStatus(channel);
   7641    }
   7642  }
   7643  return MozPromise<bool, nsresult, true>::CreateAndResolve(true, __func__);
   7644 }
   7645 
   7646 ContentMediaController* nsGlobalWindowInner::GetContentMediaController() {
   7647  if (mContentMediaController) {
   7648    return mContentMediaController;
   7649  }
   7650  if (!mBrowsingContext) {
   7651    return nullptr;
   7652  }
   7653 
   7654  mContentMediaController = new ContentMediaController(mBrowsingContext->Id());
   7655  return mContentMediaController;
   7656 }
   7657 
   7658 void nsGlobalWindowInner::SetScrollMarks(const nsTArray<uint32_t>& aScrollMarks,
   7659                                         bool aOnHScrollbar) {
   7660  mScrollMarks.Assign(aScrollMarks);
   7661  mScrollMarksOnHScrollbar = aOnHScrollbar;
   7662 
   7663  // Mark the scrollbar for repainting.
   7664  if (mDoc) {
   7665    PresShell* presShell = mDoc->GetPresShell();
   7666    if (presShell) {
   7667      ScrollContainerFrame* sf = presShell->GetRootScrollContainerFrame();
   7668      if (sf) {
   7669        sf->InvalidateScrollbars();
   7670      }
   7671    }
   7672  }
   7673 }
   7674 
   7675 /* static */
   7676 already_AddRefed<nsGlobalWindowInner> nsGlobalWindowInner::Create(
   7677    nsGlobalWindowOuter* aOuterWindow, bool aIsChrome,
   7678    WindowGlobalChild* aActor) {
   7679  RefPtr<nsGlobalWindowInner> window =
   7680      new nsGlobalWindowInner(aOuterWindow, aActor);
   7681  if (aIsChrome) {
   7682    window->mIsChrome = true;
   7683    window->mCleanMessageManager = true;
   7684  }
   7685 
   7686  if (aActor) {
   7687    aActor->InitWindowGlobal(window);
   7688  }
   7689 
   7690  window->InitWasOffline();
   7691  return window.forget();
   7692 }
   7693 
   7694 JS::loader::ModuleLoaderBase* nsGlobalWindowInner::GetModuleLoader(
   7695    JSContext* aCx) {
   7696  Document* document = GetDocument();
   7697  if (!document) {
   7698    return nullptr;
   7699  }
   7700 
   7701  ScriptLoader* loader = document->GetScriptLoader();
   7702  if (!loader) {
   7703    return nullptr;
   7704  }
   7705 
   7706  return loader->GetModuleLoader();
   7707 }
   7708 
   7709 void nsGlobalWindowInner::SetCurrentPasteDataTransfer(
   7710    DataTransfer* aDataTransfer) {
   7711  MOZ_ASSERT_IF(aDataTransfer, aDataTransfer->GetEventMessage() == ePaste);
   7712  MOZ_ASSERT_IF(aDataTransfer, aDataTransfer->ClipboardType() ==
   7713                                   Some(nsIClipboard::kGlobalClipboard));
   7714  MOZ_ASSERT_IF(aDataTransfer, aDataTransfer->GetClipboardDataSnapshot());
   7715  mCurrentPasteDataTransfer = aDataTransfer;
   7716 }
   7717 
   7718 DataTransfer* nsGlobalWindowInner::GetCurrentPasteDataTransfer() const {
   7719  return mCurrentPasteDataTransfer;
   7720 }
   7721 
   7722 TrustedTypePolicyFactory* nsGlobalWindowInner::TrustedTypes() {
   7723  if (!mTrustedTypePolicyFactory) {
   7724    mTrustedTypePolicyFactory = MakeRefPtr<TrustedTypePolicyFactory>(this);
   7725  }
   7726 
   7727  return mTrustedTypePolicyFactory;
   7728 }
   7729 
   7730 void nsPIDOMWindowInner::MaybeSetHasPointerRawUpdateEventListeners() {
   7731  if (HasPointerRawUpdateEventListeners() || !IsSecureContext()) {
   7732    return;
   7733  }
   7734  mMayHavePointerRawUpdateEventListener = true;
   7735  if (BrowserChild* const browserChild = BrowserChild::GetFrom(this)) {
   7736    browserChild->OnPointerRawUpdateEventListenerAdded(this);
   7737  }
   7738 }
   7739 
   7740 void nsPIDOMWindowInner::ClearHasPointerRawUpdateEventListeners() {
   7741  if (!HasPointerRawUpdateEventListeners()) {
   7742    return;
   7743  }
   7744  mMayHavePointerRawUpdateEventListener = false;
   7745  if (BrowserChild* const browserChild = BrowserChild::GetFrom(this)) {
   7746    browserChild->OnPointerRawUpdateEventListenerRemoved(this);
   7747  }
   7748 }
   7749 
   7750 nsIURI* nsPIDOMWindowInner::GetDocumentURI() const {
   7751  return mDoc ? mDoc->GetDocumentURI() : mDocumentURI.get();
   7752 }
   7753 
   7754 nsIURI* nsPIDOMWindowInner::GetDocBaseURI() const {
   7755  return mDoc ? mDoc->GetDocBaseURI() : mDocBaseURI.get();
   7756 }
   7757 
   7758 mozilla::dom::WindowContext* nsPIDOMWindowInner::GetWindowContext() const {
   7759  return mWindowGlobalChild ? mWindowGlobalChild->WindowContext() : nullptr;
   7760 }
   7761 
   7762 bool nsPIDOMWindowInner::RemoveFromBFCacheSync() {
   7763  if (Document* doc = GetExtantDoc()) {
   7764    return doc->RemoveFromBFCacheSync();
   7765  }
   7766  return false;
   7767 }
   7768 
   7769 void nsPIDOMWindowInner::MaybeCreateDoc() {
   7770  // XXX: Forward to outer?
   7771  MOZ_ASSERT(!mDoc);
   7772  if (nsIDocShell* docShell = GetDocShell()) {
   7773    // Note that |document| here is the same thing as our mDoc, but we
   7774    // don't have to explicitly set the member variable because the docshell
   7775    // has already called SetNewDocument().
   7776    nsCOMPtr<Document> document = docShell->GetDocument();
   7777    (void)document;
   7778  }
   7779 }
   7780 
   7781 mozilla::dom::DocGroup* nsPIDOMWindowInner::GetDocGroup() const {
   7782  Document* doc = GetExtantDoc();
   7783  if (doc) {
   7784    return doc->GetDocGroup();
   7785  }
   7786  return nullptr;
   7787 }
   7788 
   7789 mozilla::dom::BrowsingContextGroup*
   7790 nsPIDOMWindowInner::GetBrowsingContextGroup() const {
   7791  return mBrowsingContext ? mBrowsingContext->Group() : nullptr;
   7792 }
   7793 
   7794 nsIGlobalObject* nsPIDOMWindowInner::AsGlobal() {
   7795  return nsGlobalWindowInner::Cast(this);
   7796 }
   7797 
   7798 const nsIGlobalObject* nsPIDOMWindowInner::AsGlobal() const {
   7799  return nsGlobalWindowInner::Cast(this);
   7800 }
   7801 
   7802 RefPtr<GenericPromise>
   7803 nsPIDOMWindowInner::SaveStorageAccessPermissionGranted() {
   7804  WindowContext* wc = GetWindowContext();
   7805  if (wc) {
   7806    (void)wc->SetUsingStorageAccess(true);
   7807  }
   7808 
   7809  return nsGlobalWindowInner::Cast(this)->StorageAccessPermissionChanged(true);
   7810 }
   7811 
   7812 RefPtr<GenericPromise>
   7813 nsPIDOMWindowInner::SaveStorageAccessPermissionRevoked() {
   7814  WindowContext* wc = GetWindowContext();
   7815  if (wc) {
   7816    (void)wc->SetUsingStorageAccess(false);
   7817  }
   7818 
   7819  return nsGlobalWindowInner::Cast(this)->StorageAccessPermissionChanged(false);
   7820 }
   7821 
   7822 bool nsPIDOMWindowInner::UsingStorageAccess() {
   7823  WindowContext* wc = GetWindowContext();
   7824  if (!wc) {
   7825    return false;
   7826  }
   7827 
   7828  return wc->GetUsingStorageAccess();
   7829 }
   7830 
   7831 WebIdentityHandler* nsPIDOMWindowInner::GetOrCreateWebIdentityHandler() {
   7832  if (mWebIdentityHandler) {
   7833    return mWebIdentityHandler;
   7834  }
   7835  mWebIdentityHandler = new WebIdentityHandler(this);
   7836  bool success = mWebIdentityHandler->MaybeCreateActor();
   7837  if (!success) {
   7838    mWebIdentityHandler = nullptr;
   7839  }
   7840  return mWebIdentityHandler;
   7841 }
   7842 
   7843 CloseWatcherManager* nsPIDOMWindowInner::EnsureCloseWatcherManager() {
   7844  if (!mCloseWatcherManager) {
   7845    mCloseWatcherManager = new CloseWatcherManager();
   7846  }
   7847  return mCloseWatcherManager;
   7848 }
   7849 
   7850 void nsPIDOMWindowInner::NotifyCloseWatcherAdded() {
   7851  MOZ_ASSERT(mCloseWatcherManager && !mCloseWatcherManager->IsEmpty());
   7852  if (WindowContext* top = TopWindowContext(*this)) {
   7853    (void)top->SetHasActiveCloseWatcher(true);
   7854  }
   7855 }
   7856 
   7857 void nsPIDOMWindowInner::NotifyCloseWatcherRemoved() {
   7858  MOZ_ASSERT(mCloseWatcherManager);
   7859  if (WindowContext* top = TopWindowContext(*this)) {
   7860    (void)top->SetHasActiveCloseWatcher(!mCloseWatcherManager->IsEmpty());
   7861  }
   7862 }
   7863 
   7864 nsPIDOMWindowInner::nsPIDOMWindowInner(nsPIDOMWindowOuter* aOuterWindow,
   7865                                       WindowGlobalChild* aActor)
   7866    : mOuterWindow(aOuterWindow), mWindowGlobalChild(aActor) {
   7867  MOZ_ASSERT(aOuterWindow);
   7868  mBrowsingContext = aOuterWindow->GetBrowsingContext();
   7869 
   7870  if (mWindowGlobalChild) {
   7871    mWindowID = aActor->InnerWindowId();
   7872 
   7873    MOZ_ASSERT(mWindowGlobalChild->BrowsingContext() == mBrowsingContext);
   7874  } else {
   7875    mWindowID = nsContentUtils::GenerateWindowId();
   7876  }
   7877 }
   7878 
   7879 nsPIDOMWindowInner::~nsPIDOMWindowInner() = default;
   7880 
   7881 #undef FORWARD_TO_OUTER
   7882 #undef FORWARD_TO_OUTER_OR_THROW
   7883 #undef FORWARD_TO_OUTER_VOID