dom/base/nsGlobalWindow.h
author Sylvestre Ledru <sledru@mozilla.com>
Fri, 24 Feb 2017 17:04:50 +0100
changeset 489671 05d9746016f47666c00390aacc9f9d62c8ffffb4
parent 489668 cbb8fdf1daf98a15f7d57f6b08d273bdf96aa1a0
permissions -rw-r--r--
Move to 99 chars instead of 80 MozReview-Commit-ID: 6NxbMuFVI7e

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef nsGlobalWindow_h___
#define nsGlobalWindow_h___

#include "nsPIDOMWindow.h"

#include "nsTHashtable.h"
#include "nsHashKeys.h"
#include "nsRefPtrHashtable.h"
#include "nsInterfaceHashtable.h"

// Local Includes
// Helper Classes
#include "nsCOMPtr.h"
#include "nsAutoPtr.h"
#include "nsWeakReference.h"
#include "nsDataHashtable.h"
#include "nsJSThingHashtable.h"
#include "nsCycleCollectionParticipant.h"

// Interfaces Needed
#include "nsIBrowserDOMWindow.h"
#include "nsIDOMEventTarget.h"
#include "nsIInterfaceRequestor.h"
#include "nsIDOMChromeWindow.h"
#include "nsIScriptGlobalObject.h"
#include "nsIScriptObjectPrincipal.h"
#include "nsITimer.h"
#include "nsIDOMModalContentWindow.h"
#include "mozilla/EventListenerManager.h"
#include "nsIPrincipal.h"
#include "nsSize.h"
#include "mozilla/FlushType.h"
#include "prclist.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/StorageEvent.h"
#include "mozilla/dom/StorageEventBinding.h"
#include "mozilla/dom/UnionTypes.h"
#include "mozilla/ErrorResult.h"
#include "nsFrameMessageManager.h"
#include "mozilla/Attributes.h"
#include "mozilla/GuardObjects.h"
#include "mozilla/LinkedList.h"
#include "mozilla/TimeStamp.h"
#include "nsWrapperCacheInlines.h"
#include "nsIIdleObserver.h"
#include "nsIDocument.h"
#include "mozilla/dom/EventTarget.h"
#include "mozilla/dom/WindowBinding.h"
#include "Units.h"
#include "nsComponentManagerUtils.h"
#include "nsSize.h"
#include "nsCheapSets.h"
#include "mozilla/dom/ImageBitmapSource.h"
#include "mozilla/UniquePtr.h"

#define DEFAULT_HOME_PAGE "www.mozilla.org"
#define PREF_BROWSER_STARTUP_HOMEPAGE "browser.startup.homepage"

// Amount of time allowed between alert/prompt/confirm before enabling
// the stop dialog checkbox.
#define DEFAULT_SUCCESSIVE_DIALOG_TIME_LIMIT 3 // 3 sec

// Maximum number of successive dialogs before we prompt users to disable
// dialogs for this window.
#define MAX_SUCCESSIVE_DIALOG_COUNT 5

// Idle fuzz time upper limit
#define MAX_IDLE_FUZZ_TIME_MS 90000

// Min idle notification time in seconds.
#define MIN_IDLE_NOTIFICATION_TIME_S 1

class nsIArray;
class nsIBaseWindow;
class nsIContent;
class nsICSSDeclaration;
class nsIDocShellTreeOwner;
class nsIDOMOfflineResourceList;
class nsIScrollableFrame;
class nsIControllers;
class nsIJSID;
class nsIScriptContext;
class nsIScriptTimeoutHandler;
class nsITimeoutHandler;
class nsIWebBrowserChrome;
class mozIDOMWindowProxy;

class nsDOMWindowList;
class nsScreen;
class nsHistory;
class nsGlobalWindowObserver;
class nsGlobalWindow;
class nsDOMWindowUtils;
class nsIIdleService;
struct nsRect;

class nsWindowSizes;

class IdleRequestExecutor;

namespace mozilla {
class AbstractThread;
class DOMEventTargetHelper;
class ThrottledEventQueue;
namespace dom {
class BarProp;
struct ChannelPixelLayout;
class Console;
class Crypto;
class CustomElementRegistry;
class DocGroup;
class External;
class Function;
class Gamepad;
enum class ImageBitmapFormat : uint8_t;
class IdleRequest;
class IdleRequestCallback;
class IncrementalRunnable;
class Location;
class MediaQueryList;
class MozSelfSupport;
class Navigator;
class OwningExternalOrWindowProxy;
class Promise;
class PostMessageEvent;
struct RequestInit;
class RequestOrUSVString;
class Selection;
class SpeechSynthesis;
class TabGroup;
class Timeout;
class U2F;
class VRDisplay;
enum class VRDisplayEventReason : uint8_t;
class VREventObserver;
class WakeLock;
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
class WindowOrientationObserver;
#endif
class Worklet;
namespace cache {
class CacheStorage;
} // namespace cache
class IDBFactory;
} // namespace dom
} // namespace mozilla

extern already_AddRefed<nsIScriptTimeoutHandler>
NS_CreateJSTimeoutHandler(JSContext* aCx,
                          nsGlobalWindow* aWindow,
                          mozilla::dom::Function& aFunction,
                          const mozilla::dom::Sequence<JS::Value>& aArguments,
                          mozilla::ErrorResult& aError);

extern already_AddRefed<nsIScriptTimeoutHandler>
NS_CreateJSTimeoutHandler(JSContext* aCx,
                          nsGlobalWindow* aWindow,
                          const nsAString& aExpression,
                          mozilla::ErrorResult& aError);

extern const js::Class OuterWindowProxyClass;

struct IdleObserverHolder
{
  nsCOMPtr<nsIIdleObserver> mIdleObserver;
  uint32_t mTimeInS;
  bool mPrevNotificationIdle;

  IdleObserverHolder()
    : mTimeInS(0)
    , mPrevNotificationIdle(false)
  {
    MOZ_COUNT_CTOR(IdleObserverHolder);
  }

  IdleObserverHolder(const IdleObserverHolder& aOther)
    : mIdleObserver(aOther.mIdleObserver)
    , mTimeInS(aOther.mTimeInS)
    , mPrevNotificationIdle(aOther.mPrevNotificationIdle)
  {
    MOZ_COUNT_CTOR(IdleObserverHolder);
  }

  bool operator==(const IdleObserverHolder& aOther) const
  {
    return mIdleObserver == aOther.mIdleObserver && mTimeInS == aOther.mTimeInS;
  }

  ~IdleObserverHolder() { MOZ_COUNT_DTOR(IdleObserverHolder); }
};

// Helper class to manage modal dialog arguments and all their quirks.
//
// Given our clunky embedding APIs, modal dialog arguments need to be passed
// as an nsISupports parameter to WindowWatcher, get stuck inside an array of
// length 1, and then passed back to the newly-created dialog.
//
// However, we need to track both the caller-passed value as well as the
// caller's, so that we can do an origin check (even for primitives) when the
// value is accessed. This class encapsulates that magic.
//
// We also use the same machinery for |returnValue|, which needs similar origin
// checks.
class DialogValueHolder final : public nsISupports
{
public:
  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
  NS_DECL_CYCLE_COLLECTION_CLASS(DialogValueHolder)

  DialogValueHolder(nsIPrincipal* aSubject, nsIVariant* aValue)
    : mOrigin(aSubject)
    , mValue(aValue)
  {
  }
  nsresult Get(nsIPrincipal* aSubject, nsIVariant** aResult);
  void Get(JSContext* aCx,
           JS::Handle<JSObject*> aScope,
           nsIPrincipal* aSubject,
           JS::MutableHandle<JS::Value> aResult,
           mozilla::ErrorResult& aError);

private:
  virtual ~DialogValueHolder() {}

  nsCOMPtr<nsIPrincipal> mOrigin;
  nsCOMPtr<nsIVariant> mValue;
};

//*****************************************************************************
// nsGlobalWindow: Global Object for Scripting
//*****************************************************************************
// Beware that all scriptable interfaces implemented by
// nsGlobalWindow will be reachable from JS, if you make this class
// implement new interfaces you better know what you're
// doing. Security wise this is very sensitive code. --
// jst@netscape.com

// nsGlobalWindow inherits PRCList for maintaining a list of all inner
// windows still in memory for any given outer window. This list is
// needed to ensure that mOuterWindow doesn't end up dangling. The
// nature of PRCList means that the window itself is always in the
// list, and an outer window's list will also contain all inner window
// objects that are still in memory (and in reality all inner window
// object's lists also contain its outer and all other inner windows
// belonging to the same outer window, but that's an unimportant
// side effect of inheriting PRCList).

// NB: Currently nsPIDOMWindowInner and nsPIDOMWindowOuter are identical classes
// with identical member variables and identical vtables, that only differ in
// type name. nsGlobalWindow doesn't want to doubly inherit (and have two
// copies of everything), and it also doesn't want to privilege one over
// the other by making it possible to convert types through the C++ type system
// instead of our accessor methods (AsInner and AsOuter) that do dynamic
// checking. So we inherit from nsPIDOMWindow<nsISupports>, which is also
// identical to both nsPIDOMWindowInner and nsPIDOMWindowOuter, but not
// convertible to either.

class nsGlobalWindow : public mozilla::dom::EventTarget,
                       public nsPIDOMWindow<nsISupports>,
                       private nsIDOMWindowInternal,
                       public nsIScriptGlobalObject,
                       public nsIScriptObjectPrincipal,
                       public nsSupportsWeakReference,
                       public nsIInterfaceRequestor,
                       public PRCListStr
{
public:
  typedef mozilla::TimeStamp TimeStamp;
  typedef mozilla::TimeDuration TimeDuration;
  typedef nsDataHashtable<nsUint64HashKey, nsGlobalWindow*> WindowByIdTable;

  static void AssertIsOnMainThread()
#ifdef DEBUG
    ;
#else
  {
  }
#endif

  static nsGlobalWindow* Cast(nsPIDOMWindowInner* aPIWin)
  {
    return static_cast<nsGlobalWindow*>(reinterpret_cast<nsPIDOMWindow<nsISupports>*>(aPIWin));
  }
  static const nsGlobalWindow* Cast(const nsPIDOMWindowInner* aPIWin)
  {
    return static_cast<const nsGlobalWindow*>(
      reinterpret_cast<const nsPIDOMWindow<nsISupports>*>(aPIWin));
  }
  static nsGlobalWindow* Cast(mozIDOMWindow* aWin) { return Cast(nsPIDOMWindowInner::From(aWin)); }
  static nsGlobalWindow* Cast(nsPIDOMWindowOuter* aPIWin)
  {
    return static_cast<nsGlobalWindow*>(reinterpret_cast<nsPIDOMWindow<nsISupports>*>(aPIWin));
  }
  static const nsGlobalWindow* Cast(const nsPIDOMWindowOuter* aPIWin)
  {
    return static_cast<const nsGlobalWindow*>(
      reinterpret_cast<const nsPIDOMWindow<nsISupports>*>(aPIWin));
  }
  static nsGlobalWindow* Cast(mozIDOMWindowProxy* aWin)
  {
    return Cast(nsPIDOMWindowOuter::From(aWin));
  }

  // public methods
  nsPIDOMWindowOuter* GetPrivateParent();

  // callback for close event
  void ReallyCloseWindow();

  // nsISupports
  NS_DECL_CYCLE_COLLECTING_ISUPPORTS

  // nsWrapperCache
  virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> aGivenProto) override
  {
    return IsInnerWindow() || AsOuter()->EnsureInnerWindow() ? GetWrapper() : nullptr;
  }

  // nsIGlobalJSObjectHolder
  virtual JSObject* GetGlobalJSObject() override;

  // nsIScriptGlobalObject
  JSObject* FastGetGlobalJSObject() const { return GetWrapperPreserveColor(); }

  void TraceGlobalJSObject(JSTracer* aTrc);

  virtual nsresult EnsureScriptEnvironment() override;

  virtual nsIScriptContext* GetScriptContext() override;

  void PoisonOuterWindowProxy(JSObject* aObject);

  virtual bool IsBlackForCC(bool aTracingNeeded = true) override;

  // nsIScriptObjectPrincipal
  virtual nsIPrincipal* GetPrincipal() override;

  // nsIDOMWindow
  NS_DECL_NSIDOMWINDOW

  nsresult OpenJS(const nsAString& aUrl,
                  const nsAString& aName,
                  const nsAString& aOptions,
                  nsPIDOMWindowOuter** _retval);
  void CaptureEvents();
  void ReleaseEvents();
  void Dump(const nsAString& aStr);
  void SetResizable(bool aResizable) const;

  // nsIDOMEventTarget
  NS_DECL_NSIDOMEVENTTARGET

  virtual mozilla::EventListenerManager* GetExistingListenerManager() const override;

  virtual mozilla::EventListenerManager* GetOrCreateListenerManager() override;

  using mozilla::dom::EventTarget::RemoveEventListener;
  virtual void AddEventListener(const nsAString& aType,
                                mozilla::dom::EventListener* aListener,
                                const mozilla::dom::AddEventListenerOptionsOrBoolean& aOptions,
                                const mozilla::dom::Nullable<bool>& aWantsUntrusted,
                                mozilla::ErrorResult& aRv) override;
  virtual nsPIDOMWindowOuter* GetOwnerGlobalForBindings() override;

  virtual nsIGlobalObject* GetOwnerGlobal() const override
  {
    if (IsOuterWindow()) {
      return GetCurrentInnerWindowInternal();
    }

    return const_cast<nsGlobalWindow*>(this);
  }

  // nsPIDOMWindow
  virtual nsPIDOMWindowOuter* GetPrivateRoot() override;

  // Outer windows only.
  virtual void ActivateOrDeactivate(bool aActivate) override;
  virtual void SetActive(bool aActive) override;
  virtual bool IsTopLevelWindowActive() override;
  virtual void SetIsBackground(bool aIsBackground) override;
  virtual void SetChromeEventHandler(mozilla::dom::EventTarget* aChromeEventHandler) override;

  // Outer windows only.
  virtual void SetInitialPrincipalToSubject() override;

  virtual PopupControlState PushPopupControlState(PopupControlState state,
                                                  bool aForce) const override;
  virtual void PopPopupControlState(PopupControlState state) const override;
  virtual PopupControlState GetPopupControlState() const override;

  virtual already_AddRefed<nsISupports> SaveWindowState() override;
  virtual nsresult RestoreWindowState(nsISupports* aState) override;

  virtual void Suspend();
  virtual void Resume();
  virtual bool IsSuspended() const override;
  virtual void Freeze();
  virtual void Thaw();
  virtual bool IsFrozen() const override;
  virtual void SyncStateFromParentWindow();

  virtual nsresult FireDelayedDOMEvents() override;

  // Outer windows only.
  virtual bool WouldReuseInnerWindow(nsIDocument* aNewDocument) override;

  virtual void SetDocShell(nsIDocShell* aDocShell) override;
  virtual void DetachFromDocShell() override;
  virtual nsresult SetNewDocument(nsIDocument* aDocument,
                                  nsISupports* aState,
                                  bool aForceReuseInnerWindow) override;

  // Outer windows only.
  void DispatchDOMWindowCreated();

  virtual void SetOpenerWindow(nsPIDOMWindowOuter* aOpener, bool aOriginalOpener) override;

  // Outer windows only.
  virtual void EnsureSizeUpToDate() override;

  virtual void EnterModalState() override;
  virtual void LeaveModalState() override;

  // Outer windows only.
  virtual bool CanClose() override;
  virtual void ForceClose() override;

  virtual void MaybeUpdateTouchState() override;

  // Outer windows only.
  virtual bool DispatchCustomEvent(const nsAString& aEventName) override;
  bool DispatchResizeEvent(const mozilla::CSSIntSize& aSize);

  // Inner windows only.
  void RefreshCompartmentPrincipal();

  // For accessing protected field mFullScreen
  friend class FullscreenTransitionTask;

  // Outer windows only.
  virtual nsresult SetFullscreenInternal(FullscreenReason aReason,
                                         bool aIsFullscreen) override final;
  virtual void FinishFullscreenChange(bool aIsFullscreen) override final;
  bool SetWidgetFullscreen(FullscreenReason aReason,
                           bool aIsFullscreen,
                           nsIWidget* aWidget,
                           nsIScreen* aScreen);
  bool FullScreen() const;

  // Inner windows only.
  virtual void SetHasGamepadEventListener(bool aHasGamepad = true) override;
  void NotifyVREventListenerAdded();
  bool HasUsedVR() const;
  virtual void EventListenerAdded(nsIAtom* aType) override;

  // nsIInterfaceRequestor
  NS_DECL_NSIINTERFACEREQUESTOR

  // WebIDL interface.
  already_AddRefed<nsPIDOMWindowOuter> IndexedGetterOuter(uint32_t aIndex);
  already_AddRefed<nsPIDOMWindowOuter> IndexedGetter(uint32_t aIndex);

  static bool IsPrivilegedChromeWindow(JSContext* /* unused */, JSObject* aObj);

  static bool IsShowModalDialogEnabled(JSContext* /* unused */ = nullptr,
                                       JSObject* /* unused */ = nullptr);

  bool DoResolve(JSContext* aCx,
                 JS::Handle<JSObject*> aObj,
                 JS::Handle<jsid> aId,
                 JS::MutableHandle<JS::PropertyDescriptor> aDesc);
  // The return value is whether DoResolve might end up resolving the given id.
  // If in doubt, return true.
  static bool MayResolve(jsid aId);

  void GetOwnPropertyNames(JSContext* aCx, nsTArray<nsString>& aNames, mozilla::ErrorResult& aRv);

  // Object Management
  static already_AddRefed<nsGlobalWindow> Create(nsGlobalWindow* aOuterWindow);

  static nsGlobalWindow* FromSupports(nsISupports* supports)
  {
    // Make sure this matches the casts we do in QueryInterface().
    return (nsGlobalWindow*)(mozilla::dom::EventTarget*)supports;
  }
  static nsGlobalWindow* FromWrapper(nsIXPConnectWrappedNative* wrapper)
  {
    return FromSupports(wrapper->Native());
  }
  already_AddRefed<nsPIDOMWindowOuter> GetTop() override;
  nsPIDOMWindowOuter* GetScriptableTop() override;
  inline nsGlobalWindow* GetTopInternal()
  {
    nsGlobalWindow* outer = IsOuterWindow() ? this : GetOuterWindowInternal();
    nsCOMPtr<nsPIDOMWindowOuter> top = outer ? outer->GetTop() : nullptr;
    if (top) {
      return nsGlobalWindow::Cast(top);
    }
    return nullptr;
  }

  inline nsGlobalWindow* GetScriptableTopInternal()
  {
    nsPIDOMWindowOuter* top = GetScriptableTop();
    return nsGlobalWindow::Cast(top);
  }

  nsPIDOMWindowOuter* GetChildWindow(const nsAString& aName);

  // These return true if we've reached the state in this top level window
  // where we ask the user if further dialogs should be blocked.
  //
  // DialogsAreBeingAbused must be called on the scriptable top inner window.
  //
  // ShouldPromptToBlockDialogs is implemented in terms of
  // DialogsAreBeingAbused, and will get the scriptable top inner window
  // automatically.
  // Outer windows only.
  bool ShouldPromptToBlockDialogs();
  // Inner windows only.
  bool DialogsAreBeingAbused();

  // These functions are used for controlling and determining whether dialogs
  // (alert, prompt, confirm) are currently allowed in this window.  If you want
  // to temporarily disable dialogs, please use TemporarilyDisableDialogs, not
  // EnableDialogs/DisableDialogs, because correctly determining whether to
  // re-enable dialogs is actually quite difficult.
  void EnableDialogs();
  void DisableDialogs();
  // Outer windows only.
  bool AreDialogsEnabled();

  class MOZ_RAII TemporarilyDisableDialogs
  {
  public:
    // Takes an inner _or_ outer window.
    explicit TemporarilyDisableDialogs(nsGlobalWindow* aWindow MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
    ~TemporarilyDisableDialogs();

  private:
    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER

    // Always an inner window; this is the window whose dialog state we messed
    // with.  We just want to keep it alive, because we plan to poke at its
    // members in our destructor.
    RefPtr<nsGlobalWindow> mTopWindow;
    // This is not a AutoRestore<bool> because that would require careful
    // member destructor ordering, which is a bit fragile.  This way we can
    // explicitly restore things before we drop our ref to mTopWindow.
    bool mSavedDialogsEnabled;
  };
  friend class TemporarilyDisableDialogs;

  nsIScriptContext* GetContextInternal()
  {
    if (mOuterWindow) {
      return GetOuterWindowInternal()->mContext;
    }

    return mContext;
  }

  nsGlobalWindow* GetOuterWindowInternal() { return nsGlobalWindow::Cast(GetOuterWindow()); }

  nsGlobalWindow* GetCurrentInnerWindowInternal() const
  {
    MOZ_ASSERT(IsOuterWindow());
    return nsGlobalWindow::Cast(mInnerWindow);
  }

  nsGlobalWindow* EnsureInnerWindowInternal()
  {
    return nsGlobalWindow::Cast(AsOuter()->EnsureInnerWindow());
  }

  bool IsCreatingInnerWindow() const { return mCreatingInnerWindow; }

  bool IsChromeWindow() const { return mIsChrome; }

  using nsPIDOMWindow::IsModalContentWindow;
  static bool IsModalContentWindow(JSContext* aCx, JSObject* aGlobal);

  // GetScrollFrame does not flush.  Callers should do it themselves as needed,
  // depending on which info they actually want off the scrollable frame.
  nsIScrollableFrame* GetScrollFrame();

  nsresult Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData);

  // Outer windows only.
  void UnblockScriptedClosing();

  static void Init();
  static void ShutDown();
  static void CleanupCachedXBLHandlers(nsGlobalWindow* aWindow);
  static bool IsCallerChrome();

  friend class WindowStateHolder;

  NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsGlobalWindow,
                                                                   nsIDOMEventTarget)

#ifdef DEBUG
  // Call Unlink on this window. This may cause bad things to happen, so use
  // with caution.
  void RiskyUnlink();
#endif

  virtual JSObject* GetCachedXBLPrototypeHandler(nsXBLPrototypeHandler* aKey) override;

  virtual void CacheXBLPrototypeHandler(nsXBLPrototypeHandler* aKey,
                                        JS::Handle<JSObject*> aHandler) override;

  virtual bool TakeFocus(bool aFocus, uint32_t aFocusMethod) override;
  virtual void SetReadyForFocus() override;
  virtual void PageHidden() override;
  virtual nsresult DispatchAsyncHashchange(nsIURI* aOldURI, nsIURI* aNewURI) override;
  virtual nsresult DispatchSyncPopState() override;

  // Inner windows only.
  virtual void EnableDeviceSensor(uint32_t aType) override;
  virtual void DisableDeviceSensor(uint32_t aType) override;

#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
  virtual void EnableOrientationChangeListener() override;
  virtual void DisableOrientationChangeListener() override;
#endif

  virtual void EnableTimeChangeNotifications() override;
  virtual void DisableTimeChangeNotifications() override;

#ifdef MOZ_B2G
  // Inner windows only.
  virtual void EnableNetworkEvent(mozilla::EventMessage aEventMessage) override;
  virtual void DisableNetworkEvent(mozilla::EventMessage aEventMessage) override;
#endif // MOZ_B2G

  virtual nsresult SetArguments(nsIArray* aArguments) override;

  void MaybeForgiveSpamCount();
  bool IsClosedOrClosing() { return (mIsClosed || mInClose || mHavePendingClose || mCleanedUp); }

  bool HadOriginalOpener() const
  {
    MOZ_ASSERT(IsOuterWindow());
    return mHadOriginalOpener;
  }

  bool IsTopLevelWindow()
  {
    MOZ_ASSERT(IsOuterWindow());
    nsPIDOMWindowOuter* parentWindow = GetScriptableTop();
    return parentWindow == this->AsOuter();
  }

  virtual void FirePopupBlockedEvent(nsIDocument* aDoc,
                                     nsIURI* aPopupURI,
                                     const nsAString& aPopupWindowName,
                                     const nsAString& aPopupWindowFeatures) override;

  virtual uint32_t GetSerial() override { return mSerial; }

  static nsGlobalWindow* GetOuterWindowWithId(uint64_t aWindowID)
  {
    AssertIsOnMainThread();

    if (!sWindowsById) {
      return nullptr;
    }

    nsGlobalWindow* outerWindow = sWindowsById->Get(aWindowID);
    return outerWindow && !outerWindow->IsInnerWindow() ? outerWindow : nullptr;
  }

  static nsGlobalWindow* GetInnerWindowWithId(uint64_t aInnerWindowID)
  {
    AssertIsOnMainThread();

    if (!sWindowsById) {
      return nullptr;
    }

    nsGlobalWindow* innerWindow = sWindowsById->Get(aInnerWindowID);
    return innerWindow && innerWindow->IsInnerWindow() ? innerWindow : nullptr;
  }

  static WindowByIdTable* GetWindowsTable()
  {
    AssertIsOnMainThread();

    return sWindowsById;
  }

  void AddSizeOfIncludingThis(nsWindowSizes* aWindowSizes) const;

  // Inner windows only.
  void AddEventTargetObject(mozilla::DOMEventTargetHelper* aObject);
  void RemoveEventTargetObject(mozilla::DOMEventTargetHelper* aObject);

  void NotifyIdleObserver(IdleObserverHolder* aIdleObserverHolder, bool aCallOnidle);
  nsresult HandleIdleActiveEvent();
  bool ContainsIdleObserver(nsIIdleObserver* aIdleObserver, uint32_t timeInS);
  void HandleIdleObserverCallback();

  void AllowScriptsToClose() { mAllowScriptsToClose = true; }

  enum SlowScriptResponse
  {
    ContinueSlowScript = 0,
    ContinueSlowScriptAndKeepNotifying,
    AlwaysContinueSlowScript,
    KillSlowScript
  };
  SlowScriptResponse ShowSlowScriptDialog();

  // Inner windows only.
  void AddGamepad(uint32_t aIndex, mozilla::dom::Gamepad* aGamepad);
  void RemoveGamepad(uint32_t aIndex);
  void GetGamepads(nsTArray<RefPtr<mozilla::dom::Gamepad>>& aGamepads);
  already_AddRefed<mozilla::dom::Gamepad> GetGamepad(uint32_t aIndex);
  void SetHasSeenGamepadInput(bool aHasSeen);
  bool HasSeenGamepadInput();
  void SyncGamepadState();

  // Inner windows only.
  // Enable/disable updates for gamepad input.
  void EnableGamepadUpdates();
  void DisableGamepadUpdates();

  // Inner windows only.
  // Enable/disable updates for VR
  void EnableVRUpdates();
  void DisableVRUpdates();

  // Update the VR displays for this window
  bool UpdateVRDisplays(nsTArray<RefPtr<mozilla::dom::VRDisplay>>& aDisplays);

  // Inner windows only.
  // Called to inform that the set of active VR displays has changed.
  void NotifyActiveVRDisplaysChanged();

  void DispatchVRDisplayActivate(uint32_t aDisplayID, mozilla::dom::VRDisplayEventReason aReason);
  void DispatchVRDisplayDeactivate(uint32_t aDisplayID,
                                   mozilla::dom::VRDisplayEventReason aReason);
  void DispatchVRDisplayConnect(uint32_t aDisplayID);
  void DispatchVRDisplayDisconnect(uint32_t aDisplayID);
  void DispatchVRDisplayPresentChange(uint32_t aDisplayID);

#define EVENT(name_, id_, type_, struct_)                                                         \
  mozilla::dom::EventHandlerNonNull* GetOn##name_()                                               \
  {                                                                                               \
    mozilla::EventListenerManager* elm = GetExistingListenerManager();                            \
    return elm ? elm->GetEventHandler(nsGkAtoms::on##name_, EmptyString()) : nullptr;             \
  }                                                                                               \
  void SetOn##name_(mozilla::dom::EventHandlerNonNull* handler)                                   \
  {                                                                                               \
    mozilla::EventListenerManager* elm = GetOrCreateListenerManager();                            \
    if (elm) {                                                                                    \
      elm->SetEventHandler(nsGkAtoms::on##name_, EmptyString(), handler);                         \
    }                                                                                             \
  }
#define ERROR_EVENT(name_, id_, type_, struct_)                                                   \
  mozilla::dom::OnErrorEventHandlerNonNull* GetOn##name_()                                        \
  {                                                                                               \
    mozilla::EventListenerManager* elm = GetExistingListenerManager();                            \
    return elm ? elm->GetOnErrorEventHandler() : nullptr;                                         \
  }                                                                                               \
  void SetOn##name_(mozilla::dom::OnErrorEventHandlerNonNull* handler)                            \
  {                                                                                               \
    mozilla::EventListenerManager* elm = GetOrCreateListenerManager();                            \
    if (elm) {                                                                                    \
      elm->SetEventHandler(handler);                                                              \
    }                                                                                             \
  }
#define BEFOREUNLOAD_EVENT(name_, id_, type_, struct_)                                            \
  mozilla::dom::OnBeforeUnloadEventHandlerNonNull* GetOn##name_()                                 \
  {                                                                                               \
    mozilla::EventListenerManager* elm = GetExistingListenerManager();                            \
    return elm ? elm->GetOnBeforeUnloadEventHandler() : nullptr;                                  \
  }                                                                                               \
  void SetOn##name_(mozilla::dom::OnBeforeUnloadEventHandlerNonNull* handler)                     \
  {                                                                                               \
    mozilla::EventListenerManager* elm = GetOrCreateListenerManager();                            \
    if (elm) {                                                                                    \
      elm->SetEventHandler(handler);                                                              \
    }                                                                                             \
  }
#define WINDOW_ONLY_EVENT EVENT
#define TOUCH_EVENT EVENT
#include "mozilla/EventNameList.h"
#undef TOUCH_EVENT
#undef WINDOW_ONLY_EVENT
#undef BEFOREUNLOAD_EVENT
#undef ERROR_EVENT
#undef EVENT

  nsISupports* GetParentObject() { return nullptr; }

  static JSObject* CreateNamedPropertiesObject(JSContext* aCx, JS::Handle<JSObject*> aProto);

  nsGlobalWindow* Window();
  nsGlobalWindow* Self();
  nsIDocument* GetDocument() { return GetDoc(); }
  void GetNameOuter(nsAString& aName);
  void GetName(nsAString& aName, mozilla::ErrorResult& aError);
  void SetNameOuter(const nsAString& aName, mozilla::ErrorResult& aError);
  void SetName(const nsAString& aName, mozilla::ErrorResult& aError);
  mozilla::dom::Location* GetLocation(mozilla::ErrorResult& aError);
  nsIDOMLocation* GetLocation() override;
  nsHistory* GetHistory(mozilla::ErrorResult& aError);
  mozilla::dom::CustomElementRegistry* CustomElements() override;
  mozilla::dom::BarProp* GetLocationbar(mozilla::ErrorResult& aError);
  mozilla::dom::BarProp* GetMenubar(mozilla::ErrorResult& aError);
  mozilla::dom::BarProp* GetPersonalbar(mozilla::ErrorResult& aError);
  mozilla::dom::BarProp* GetScrollbars(mozilla::ErrorResult& aError);
  mozilla::dom::BarProp* GetStatusbar(mozilla::ErrorResult& aError);
  mozilla::dom::BarProp* GetToolbar(mozilla::ErrorResult& aError);
  void GetStatusOuter(nsAString& aStatus);
  void GetStatus(nsAString& aStatus, mozilla::ErrorResult& aError);
  void SetStatusOuter(const nsAString& aStatus);
  void SetStatus(const nsAString& aStatus, mozilla::ErrorResult& aError);
  void CloseOuter(bool aTrustedCaller);
  void Close(mozilla::ErrorResult& aError);
  nsresult Close() override;
  bool GetClosedOuter();
  bool GetClosed(mozilla::ErrorResult& aError);
  bool Closed() override;
  void StopOuter(mozilla::ErrorResult& aError);
  void Stop(mozilla::ErrorResult& aError);
  void FocusOuter(mozilla::ErrorResult& aError);
  void Focus(mozilla::ErrorResult& aError);
  nsresult Focus() override;
  void BlurOuter();
  void Blur(mozilla::ErrorResult& aError);
  already_AddRefed<nsPIDOMWindowOuter> GetFramesOuter();
  already_AddRefed<nsIDOMWindowCollection> GetFrames() override;
  already_AddRefed<nsPIDOMWindowOuter> GetFrames(mozilla::ErrorResult& aError);
  uint32_t Length();
  already_AddRefed<nsPIDOMWindowOuter> GetTopOuter();
  already_AddRefed<nsPIDOMWindowOuter> GetTop(mozilla::ErrorResult& aError);

  nsresult GetPrompter(nsIPrompt** aPrompt) override;

protected:
  explicit nsGlobalWindow(nsGlobalWindow* aOuterWindow);
  nsPIDOMWindowOuter* GetOpenerWindowOuter();
  // Initializes the mWasOffline member variable
  void InitWasOffline();

public:
  nsPIDOMWindowOuter* GetSanitizedOpener(nsPIDOMWindowOuter* aOpener);

  nsPIDOMWindowOuter* GetOpenerWindow(mozilla::ErrorResult& aError);
  void GetOpener(JSContext* aCx,
                 JS::MutableHandle<JS::Value> aRetval,
                 mozilla::ErrorResult& aError);
  already_AddRefed<nsPIDOMWindowOuter> GetOpener() override;
  void SetOpener(JSContext* aCx, JS::Handle<JS::Value> aOpener, mozilla::ErrorResult& aError);
  already_AddRefed<nsPIDOMWindowOuter> GetParentOuter();
  already_AddRefed<nsPIDOMWindowOuter> GetParent(mozilla::ErrorResult& aError);
  already_AddRefed<nsPIDOMWindowOuter> GetParent() override;
  nsPIDOMWindowOuter* GetScriptableParent() override;
  nsPIDOMWindowOuter* GetScriptableParentOrNull() override;
  mozilla::dom::Element* GetFrameElementOuter(nsIPrincipal& aSubjectPrincipal);
  mozilla::dom::Element* GetFrameElement(nsIPrincipal& aSubjectPrincipal,
                                         mozilla::ErrorResult& aError);
  already_AddRefed<nsIDOMElement> GetFrameElement() override;
  already_AddRefed<nsPIDOMWindowOuter> OpenOuter(const nsAString& aUrl,
                                                 const nsAString& aName,
                                                 const nsAString& aOptions,
                                                 mozilla::ErrorResult& aError);
  already_AddRefed<nsPIDOMWindowOuter> Open(const nsAString& aUrl,
                                            const nsAString& aName,
                                            const nsAString& aOptions,
                                            mozilla::ErrorResult& aError);
  nsresult Open(const nsAString& aUrl,
                const nsAString& aName,
                const nsAString& aOptions,
                nsIDocShellLoadInfo* aLoadInfo,
                bool aForceNoOpener,
                nsPIDOMWindowOuter** _retval) override;
  mozilla::dom::Navigator* GetNavigator(mozilla::ErrorResult& aError);
  nsIDOMNavigator* GetNavigator() override;
  nsIDOMOfflineResourceList* GetApplicationCache(mozilla::ErrorResult& aError);
  already_AddRefed<nsIDOMOfflineResourceList> GetApplicationCache() override;

#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
  int16_t Orientation(mozilla::dom::CallerType aCallerType) const;
#endif

  mozilla::dom::Console* GetConsole(mozilla::ErrorResult& aRv);

  // https://w3c.github.io/webappsec-secure-contexts/#dom-window-issecurecontext
  bool IsSecureContext() const;
  bool IsSecureContextIfOpenerIgnored() const;

  void GetSidebar(mozilla::dom::OwningExternalOrWindowProxy& aResult, mozilla::ErrorResult& aRv);
  already_AddRefed<mozilla::dom::External> GetExternal(mozilla::ErrorResult& aRv);

  // Exposed only for testing
  static bool TokenizeDialogOptions(nsAString& aToken,
                                    nsAString::const_iterator& aIter,
                                    nsAString::const_iterator aEnd);
  static void ConvertDialogOptions(const nsAString& aOptions, nsAString& aResult);

  mozilla::dom::Worklet* GetAudioWorklet(mozilla::ErrorResult& aRv);

  mozilla::dom::Worklet* GetPaintWorklet(mozilla::ErrorResult& aRv);

  void GetAppLocales(nsTArray<nsString>& aLocales);

protected:
  bool AlertOrConfirm(bool aAlert,
                      const nsAString& aMessage,
                      nsIPrincipal& aSubjectPrincipal,
                      mozilla::ErrorResult& aError);

public:
  void Alert(nsIPrincipal& aSubjectPrincipal, mozilla::ErrorResult& aError);
  void AlertOuter(const nsAString& aMessage,
                  nsIPrincipal& aSubjectPrincipal,
                  mozilla::ErrorResult& aError);
  void Alert(const nsAString& aMessage,
             nsIPrincipal& aSubjectPrincipal,
             mozilla::ErrorResult& aError);
  bool ConfirmOuter(const nsAString& aMessage,
                    nsIPrincipal& aSubjectPrincipal,
                    mozilla::ErrorResult& aError);
  bool Confirm(const nsAString& aMessage,
               nsIPrincipal& aSubjectPrincipal,
               mozilla::ErrorResult& aError);
  void PromptOuter(const nsAString& aMessage,
                   const nsAString& aInitial,
                   nsAString& aReturn,
                   nsIPrincipal& aSubjectPrincipal,
                   mozilla::ErrorResult& aError);
  void Prompt(const nsAString& aMessage,
              const nsAString& aInitial,
              nsAString& aReturn,
              nsIPrincipal& aSubjectPrincipal,
              mozilla::ErrorResult& aError);
  already_AddRefed<mozilla::dom::cache::CacheStorage> GetCaches(mozilla::ErrorResult& aRv);
  already_AddRefed<mozilla::dom::Promise> Fetch(const mozilla::dom::RequestOrUSVString& aInput,
                                                const mozilla::dom::RequestInit& aInit,
                                                mozilla::dom::CallerType aCallerType,
                                                mozilla::ErrorResult& aRv);
  void PrintOuter(mozilla::ErrorResult& aError);
  void Print(mozilla::ErrorResult& aError);
  void ShowModalDialog(JSContext* aCx,
                       const nsAString& aUrl,
                       JS::Handle<JS::Value> aArgument,
                       const nsAString& aOptions,
                       JS::MutableHandle<JS::Value> aRetval,
                       nsIPrincipal& aSubjectPrincipal,
                       mozilla::ErrorResult& aError);
  void PostMessageMoz(JSContext* aCx,
                      JS::Handle<JS::Value> aMessage,
                      const nsAString& aTargetOrigin,
                      const mozilla::dom::Sequence<JSObject*>& aTransfer,
                      nsIPrincipal& aSubjectPrincipal,
                      mozilla::ErrorResult& aError);
  int32_t SetTimeout(JSContext* aCx,
                     mozilla::dom::Function& aFunction,
                     int32_t aTimeout,
                     const mozilla::dom::Sequence<JS::Value>& aArguments,
                     mozilla::ErrorResult& aError);
  int32_t SetTimeout(JSContext* aCx,
                     const nsAString& aHandler,
                     int32_t aTimeout,
                     const mozilla::dom::Sequence<JS::Value>& /* unused */,
                     mozilla::ErrorResult& aError);
  void ClearTimeout(int32_t aHandle);
  int32_t SetInterval(JSContext* aCx,
                      mozilla::dom::Function& aFunction,
                      const mozilla::dom::Optional<int32_t>& aTimeout,
                      const mozilla::dom::Sequence<JS::Value>& aArguments,
                      mozilla::ErrorResult& aError);
  int32_t SetInterval(JSContext* aCx,
                      const nsAString& aHandler,
                      const mozilla::dom::Optional<int32_t>& aTimeout,
                      const mozilla::dom::Sequence<JS::Value>& /* unused */,
                      mozilla::ErrorResult& aError);
  void ClearInterval(int32_t aHandle);
  void GetOrigin(nsAString& aOrigin);
  void Atob(const nsAString& aAsciiBase64String,
            nsAString& aBinaryData,
            mozilla::ErrorResult& aError);
  void Btoa(const nsAString& aBinaryData,
            nsAString& aAsciiBase64String,
            mozilla::ErrorResult& aError);
  mozilla::dom::Storage* GetSessionStorage(mozilla::ErrorResult& aError);
  mozilla::dom::Storage* GetLocalStorage(mozilla::ErrorResult& aError);
  mozilla::dom::Selection* GetSelectionOuter();
  mozilla::dom::Selection* GetSelection(mozilla::ErrorResult& aError);
  already_AddRefed<nsISelection> GetSelection() override;
  mozilla::dom::IDBFactory* GetIndexedDB(mozilla::ErrorResult& aError);
  already_AddRefed<nsICSSDeclaration> GetComputedStyle(mozilla::dom::Element& aElt,
                                                       const nsAString& aPseudoElt,
                                                       mozilla::ErrorResult& aError) override;
  already_AddRefed<mozilla::dom::MediaQueryList> MatchMediaOuter(const nsAString& aQuery);
  already_AddRefed<mozilla::dom::MediaQueryList> MatchMedia(const nsAString& aQuery,
                                                            mozilla::ErrorResult& aError);
  nsScreen* GetScreen(mozilla::ErrorResult& aError);
  nsIDOMScreen* GetScreen() override;
  void MoveToOuter(int32_t aXPos,
                   int32_t aYPos,
                   mozilla::dom::CallerType aCallerType,
                   mozilla::ErrorResult& aError);
  void MoveTo(int32_t aXPos,
              int32_t aYPos,
              mozilla::dom::CallerType aCallerType,
              mozilla::ErrorResult& aError);
  void MoveByOuter(int32_t aXDif,
                   int32_t aYDif,
                   mozilla::dom::CallerType aCallerType,
                   mozilla::ErrorResult& aError);
  void MoveBy(int32_t aXDif,
              int32_t aYDif,
              mozilla::dom::CallerType aCallerType,
              mozilla::ErrorResult& aError);
  nsresult MoveBy(int32_t aXDif, int32_t aYDif) override;
  void ResizeToOuter(int32_t aWidth,
                     int32_t aHeight,
                     mozilla::dom::CallerType aCallerType,
                     mozilla::ErrorResult& aError);
  void ResizeTo(int32_t aWidth,
                int32_t aHeight,
                mozilla::dom::CallerType aCallerType,
                mozilla::ErrorResult& aError);
  void ResizeByOuter(int32_t aWidthDif,
                     int32_t aHeightDif,
                     mozilla::dom::CallerType aCallerType,
                     mozilla::ErrorResult& aError);
  void ResizeBy(int32_t aWidthDif,
                int32_t aHeightDif,
                mozilla::dom::CallerType aCallerType,
                mozilla::ErrorResult& aError);
  void Scroll(double aXScroll, double aYScroll);
  void Scroll(const mozilla::dom::ScrollToOptions& aOptions);
  void ScrollTo(double aXScroll, double aYScroll);
  void ScrollTo(const mozilla::dom::ScrollToOptions& aOptions);
  void ScrollBy(double aXScrollDif, double aYScrollDif);
  void ScrollBy(const mozilla::dom::ScrollToOptions& aOptions);
  void ScrollByLines(int32_t numLines, const mozilla::dom::ScrollOptions& aOptions);
  void ScrollByPages(int32_t numPages, const mozilla::dom::ScrollOptions& aOptions);
  void MozScrollSnap();
  void GetInnerWidth(JSContext* aCx,
                     JS::MutableHandle<JS::Value> aValue,
                     mozilla::dom::CallerType aCallerType,
                     mozilla::ErrorResult& aError);
  void SetInnerWidth(JSContext* aCx,
                     JS::Handle<JS::Value> aValue,
                     mozilla::dom::CallerType aCallerType,
                     mozilla::ErrorResult& aError);
  void GetInnerHeight(JSContext* aCx,
                      JS::MutableHandle<JS::Value> aValue,
                      mozilla::dom::CallerType aCallerType,
                      mozilla::ErrorResult& aError);
  void SetInnerHeight(JSContext* aCx,
                      JS::Handle<JS::Value> aValue,
                      mozilla::dom::CallerType aCallerType,
                      mozilla::ErrorResult& aError);
  int32_t GetScrollXOuter();
  int32_t GetScrollX(mozilla::ErrorResult& aError);
  int32_t GetPageXOffset(mozilla::ErrorResult& aError) { return GetScrollX(aError); }
  int32_t GetScrollYOuter();
  int32_t GetScrollY(mozilla::ErrorResult& aError);
  int32_t GetPageYOffset(mozilla::ErrorResult& aError) { return GetScrollY(aError); }
  void GetScreenX(JSContext* aCx,
                  JS::MutableHandle<JS::Value> aValue,
                  mozilla::dom::CallerType aCallerType,
                  mozilla::ErrorResult& aError);
  void SetScreenX(JSContext* aCx,
                  JS::Handle<JS::Value> aValue,
                  mozilla::dom::CallerType aCallerType,
                  mozilla::ErrorResult& aError);
  void GetScreenY(JSContext* aCx,
                  JS::MutableHandle<JS::Value> aValue,
                  mozilla::dom::CallerType aCallerType,
                  mozilla::ErrorResult& aError);
  void SetScreenY(JSContext* aCx,
                  JS::Handle<JS::Value> aValue,
                  mozilla::dom::CallerType aCallerType,
                  mozilla::ErrorResult& aError);
  void GetOuterWidth(JSContext* aCx,
                     JS::MutableHandle<JS::Value> aValue,
                     mozilla::dom::CallerType aCallerType,
                     mozilla::ErrorResult& aError);
  void SetOuterWidth(JSContext* aCx,
                     JS::Handle<JS::Value> aValue,
                     mozilla::dom::CallerType aCallerType,
                     mozilla::ErrorResult& aError);
  void GetOuterHeight(JSContext* aCx,
                      JS::MutableHandle<JS::Value> aValue,
                      mozilla::dom::CallerType aCallerType,
                      mozilla::ErrorResult& aError);
  void SetOuterHeight(JSContext* aCx,
                      JS::Handle<JS::Value> aValue,
                      mozilla::dom::CallerType aCallerType,
                      mozilla::ErrorResult& aError);
  int32_t RequestAnimationFrame(mozilla::dom::FrameRequestCallback& aCallback,
                                mozilla::ErrorResult& aError);
  void CancelAnimationFrame(int32_t aHandle, mozilla::ErrorResult& aError);

  uint32_t RequestIdleCallback(JSContext* aCx,
                               mozilla::dom::IdleRequestCallback& aCallback,
                               const mozilla::dom::IdleRequestOptions& aOptions,
                               mozilla::ErrorResult& aError);
  void CancelIdleCallback(uint32_t aHandle);

#ifdef MOZ_WEBSPEECH
  mozilla::dom::SpeechSynthesis* GetSpeechSynthesis(mozilla::ErrorResult& aError);
  bool HasActiveSpeechSynthesis();
#endif
  already_AddRefed<nsICSSDeclaration> GetDefaultComputedStyle(mozilla::dom::Element& aElt,
                                                              const nsAString& aPseudoElt,
                                                              mozilla::ErrorResult& aError);
  void SizeToContentOuter(mozilla::dom::CallerType aCallerType, mozilla::ErrorResult& aError);
  void SizeToContent(mozilla::dom::CallerType aCallerType, mozilla::ErrorResult& aError);
  mozilla::dom::Crypto* GetCrypto(mozilla::ErrorResult& aError);
  mozilla::dom::U2F* GetU2f(mozilla::ErrorResult& aError);
  nsIControllers* GetControllersOuter(mozilla::ErrorResult& aError);
  nsIControllers* GetControllers(mozilla::ErrorResult& aError);
  nsresult GetControllers(nsIControllers** aControllers) override;
  mozilla::dom::Element* GetRealFrameElementOuter();
  mozilla::dom::Element* GetRealFrameElement(mozilla::ErrorResult& aError);
  float GetMozInnerScreenXOuter(mozilla::dom::CallerType aCallerType);
  float GetMozInnerScreenX(mozilla::dom::CallerType aCallerType, mozilla::ErrorResult& aError);
  float GetMozInnerScreenYOuter(mozilla::dom::CallerType aCallerType);
  float GetMozInnerScreenY(mozilla::dom::CallerType aCallerType, mozilla::ErrorResult& aError);
  float GetDevicePixelRatioOuter(mozilla::dom::CallerType aCallerType);
  float GetDevicePixelRatio(mozilla::dom::CallerType aCallerType, mozilla::ErrorResult& aError);
  int32_t GetScrollMinX(mozilla::ErrorResult& aError);
  int32_t GetScrollMinY(mozilla::ErrorResult& aError);
  int32_t GetScrollMaxX(mozilla::ErrorResult& aError);
  int32_t GetScrollMaxY(mozilla::ErrorResult& aError);
  bool GetFullScreenOuter();
  bool GetFullScreen(mozilla::ErrorResult& aError);
  bool GetFullScreen() override;
  void SetFullScreenOuter(bool aFullScreen, mozilla::ErrorResult& aError);
  void SetFullScreen(bool aFullScreen, mozilla::ErrorResult& aError);
  nsresult SetFullScreen(bool aFullScreen) override;
  void BackOuter(mozilla::ErrorResult& aError);
  void Back(mozilla::ErrorResult& aError);
  void ForwardOuter(mozilla::ErrorResult& aError);
  void Forward(mozilla::ErrorResult& aError);
  void HomeOuter(mozilla::ErrorResult& aError);
  void Home(mozilla::ErrorResult& aError);
  bool FindOuter(const nsAString& aString,
                 bool aCaseSensitive,
                 bool aBackwards,
                 bool aWrapAround,
                 bool aWholeWord,
                 bool aSearchInFrames,
                 bool aShowDialog,
                 mozilla::ErrorResult& aError);
  bool Find(const nsAString& aString,
            bool aCaseSensitive,
            bool aBackwards,
            bool aWrapAround,
            bool aWholeWord,
            bool aSearchInFrames,
            bool aShowDialog,
            mozilla::ErrorResult& aError);
  uint64_t GetMozPaintCountOuter();
  uint64_t GetMozPaintCount(mozilla::ErrorResult& aError);

  bool ShouldResistFingerprinting();

  mozilla::dom::MozSelfSupport* GetMozSelfSupport(mozilla::ErrorResult& aError);

  already_AddRefed<nsPIDOMWindowOuter> OpenDialogOuter(
    JSContext* aCx,
    const nsAString& aUrl,
    const nsAString& aName,
    const nsAString& aOptions,
    const mozilla::dom::Sequence<JS::Value>& aExtraArgument,
    mozilla::ErrorResult& aError);
  already_AddRefed<nsPIDOMWindowOuter> OpenDialog(
    JSContext* aCx,
    const nsAString& aUrl,
    const nsAString& aName,
    const nsAString& aOptions,
    const mozilla::dom::Sequence<JS::Value>& aExtraArgument,
    mozilla::ErrorResult& aError);
  nsresult OpenDialog(const nsAString& aUrl,
                      const nsAString& aName,
                      const nsAString& aOptions,
                      nsISupports* aExtraArgument,
                      nsPIDOMWindowOuter** _retval) override;
  nsresult UpdateCommands(const nsAString& anAction, nsISelection* aSel, int16_t aReason) override;

  already_AddRefed<nsPIDOMWindowOuter> GetContentInternal(mozilla::ErrorResult& aError,
                                                          mozilla::dom::CallerType aCallerType);
  void GetContentOuter(JSContext* aCx,
                       JS::MutableHandle<JSObject*> aRetval,
                       mozilla::dom::CallerType aCallerType,
                       mozilla::ErrorResult& aError);
  void GetContent(JSContext* aCx,
                  JS::MutableHandle<JSObject*> aRetval,
                  mozilla::dom::CallerType aCallerType,
                  mozilla::ErrorResult& aError);
  already_AddRefed<nsPIDOMWindowOuter> GetContent()
  {
    MOZ_ASSERT(IsOuterWindow());
    mozilla::IgnoredErrorResult ignored;
    nsCOMPtr<nsPIDOMWindowOuter> win =
      GetContentInternal(ignored, mozilla::dom::CallerType::System);
    return win.forget();
  }

  void Get_content(JSContext* aCx,
                   JS::MutableHandle<JSObject*> aRetval,
                   mozilla::dom::SystemCallerGuarantee aCallerType,
                   mozilla::ErrorResult& aError)
  {
    if (mDoc) {
      mDoc->WarnOnceAbout(nsIDocument::eWindow_Content);
    }
    GetContent(aCx, aRetval, aCallerType, aError);
  }

  already_AddRefed<mozilla::dom::Promise> CreateImageBitmap(
    const mozilla::dom::ImageBitmapSource& aImage,
    mozilla::ErrorResult& aRv);

  already_AddRefed<mozilla::dom::Promise> CreateImageBitmap(
    const mozilla::dom::ImageBitmapSource& aImage,
    int32_t aSx,
    int32_t aSy,
    int32_t aSw,
    int32_t aSh,
    mozilla::ErrorResult& aRv);

  already_AddRefed<mozilla::dom::Promise> CreateImageBitmap(
    const mozilla::dom::ImageBitmapSource& aImage,
    int32_t aOffset,
    int32_t aLength,
    mozilla::dom::ImageBitmapFormat aFormat,
    const mozilla::dom::Sequence<mozilla::dom::ChannelPixelLayout>& aLayout,
    mozilla::ErrorResult& aRv);

  // ChromeWindow bits.  Do NOT call these unless your window is in
  // fact an nsGlobalChromeWindow.
  uint16_t WindowState();
  nsIBrowserDOMWindow* GetBrowserDOMWindowOuter();
  nsIBrowserDOMWindow* GetBrowserDOMWindow(mozilla::ErrorResult& aError);
  void SetBrowserDOMWindowOuter(nsIBrowserDOMWindow* aBrowserWindow);
  void SetBrowserDOMWindow(nsIBrowserDOMWindow* aBrowserWindow, mozilla::ErrorResult& aError);
  void GetAttention(mozilla::ErrorResult& aError);
  void GetAttentionWithCycleCount(int32_t aCycleCount, mozilla::ErrorResult& aError);
  void SetCursorOuter(const nsAString& aCursor, mozilla::ErrorResult& aError);
  void SetCursor(const nsAString& aCursor, mozilla::ErrorResult& aError);
  void Maximize();
  void Minimize();
  void Restore();
  void NotifyDefaultButtonLoaded(mozilla::dom::Element& aDefaultButton,
                                 mozilla::ErrorResult& aError);
  nsIMessageBroadcaster* GetMessageManager(mozilla::ErrorResult& aError);
  nsIMessageBroadcaster* GetGroupMessageManager(const nsAString& aGroup,
                                                mozilla::ErrorResult& aError);
  void BeginWindowMove(mozilla::dom::Event& aMouseDownEvent,
                       mozilla::dom::Element* aPanel,
                       mozilla::ErrorResult& aError);

  void GetDialogArgumentsOuter(JSContext* aCx,
                               JS::MutableHandle<JS::Value> aRetval,
                               nsIPrincipal& aSubjectPrincipal,
                               mozilla::ErrorResult& aError);
  void GetDialogArguments(JSContext* aCx,
                          JS::MutableHandle<JS::Value> aRetval,
                          nsIPrincipal& aSubjectPrincipal,
                          mozilla::ErrorResult& aError);
  void GetReturnValueOuter(JSContext* aCx,
                           JS::MutableHandle<JS::Value> aReturnValue,
                           nsIPrincipal& aSubjectPrincipal,
                           mozilla::ErrorResult& aError);
  void GetReturnValue(JSContext* aCx,
                      JS::MutableHandle<JS::Value> aReturnValue,
                      nsIPrincipal& aSubjectPrincipal,
                      mozilla::ErrorResult& aError);
  void SetReturnValueOuter(JSContext* aCx,
                           JS::Handle<JS::Value> aReturnValue,
                           nsIPrincipal& aSubjectPrincipal,
                           mozilla::ErrorResult& aError);
  void SetReturnValue(JSContext* aCx,
                      JS::Handle<JS::Value> aReturnValue,
                      nsIPrincipal& aSubjectPrincipal,
                      mozilla::ErrorResult& aError);

  void GetInterface(JSContext* aCx,
                    nsIJSID* aIID,
                    JS::MutableHandle<JS::Value> aRetval,
                    mozilla::ErrorResult& aError);

  already_AddRefed<nsWindowRoot> GetWindowRootOuter();
  already_AddRefed<nsWindowRoot> GetWindowRoot(mozilla::ErrorResult& aError);

  mozilla::dom::Performance* GetPerformance();

protected:
  // Web IDL helpers

  // Redefine the property called aPropName on this window object to be a value
  // property with the value aValue, much like we would do for a [Replaceable]
  // property in IDL.
  void RedefineProperty(JSContext* aCx,
                        const char* aPropName,
                        JS::Handle<JS::Value> aValue,
                        mozilla::ErrorResult& aError);

  // Implementation guts for our writable IDL attributes that are really
  // supposed to be readonly replaceable.
  typedef int32_t (nsGlobalWindow::*WindowCoordGetter)(mozilla::dom::CallerType aCallerType,
                                                       mozilla::ErrorResult&);
  typedef void (nsGlobalWindow::*WindowCoordSetter)(int32_t,
                                                    mozilla::dom::CallerType aCallerType,
                                                    mozilla::ErrorResult&);
  void GetReplaceableWindowCoord(JSContext* aCx,
                                 WindowCoordGetter aGetter,
                                 JS::MutableHandle<JS::Value> aRetval,
                                 mozilla::dom::CallerType aCallerType,
                                 mozilla::ErrorResult& aError);
  void SetReplaceableWindowCoord(JSContext* aCx,
                                 WindowCoordSetter aSetter,
                                 JS::Handle<JS::Value> aValue,
                                 const char* aPropName,
                                 mozilla::dom::CallerType aCallerType,
                                 mozilla::ErrorResult& aError);
  // And the implementations of WindowCoordGetter/WindowCoordSetter.
public:
  int32_t GetInnerWidthOuter(mozilla::ErrorResult& aError);

protected:
  int32_t GetInnerWidth(mozilla::dom::CallerType aCallerType, mozilla::ErrorResult& aError);
  nsresult GetInnerWidth(int32_t* aWidth) override;
  void SetInnerWidthOuter(int32_t aInnerWidth,
                          mozilla::dom::CallerType aCallerType,
                          mozilla::ErrorResult& aError);
  void SetInnerWidth(int32_t aInnerWidth,
                     mozilla::dom::CallerType aCallerType,
                     mozilla::ErrorResult& aError);

public:
  int32_t GetInnerHeightOuter(mozilla::ErrorResult& aError);

protected:
  int32_t GetInnerHeight(mozilla::dom::CallerType aCallerType, mozilla::ErrorResult& aError);
  nsresult GetInnerHeight(int32_t* aHeight) override;
  void SetInnerHeightOuter(int32_t aInnerHeight,
                           mozilla::dom::CallerType aCallerType,
                           mozilla::ErrorResult& aError);
  void SetInnerHeight(int32_t aInnerHeight,
                      mozilla::dom::CallerType aCallerType,
                      mozilla::ErrorResult& aError);
  int32_t GetScreenXOuter(mozilla::dom::CallerType aCallerType, mozilla::ErrorResult& aError);
  int32_t GetScreenX(mozilla::dom::CallerType aCallerType, mozilla::ErrorResult& aError);
  void SetScreenXOuter(int32_t aScreenX,
                       mozilla::dom::CallerType aCallerType,
                       mozilla::ErrorResult& aError);
  void SetScreenX(int32_t aScreenX,
                  mozilla::dom::CallerType aCallerType,
                  mozilla::ErrorResult& aError);
  int32_t GetScreenYOuter(mozilla::dom::CallerType aCallerType, mozilla::ErrorResult& aError);
  int32_t GetScreenY(mozilla::dom::CallerType aCallerType, mozilla::ErrorResult& aError);
  void SetScreenYOuter(int32_t aScreenY,
                       mozilla::dom::CallerType aCallerType,
                       mozilla::ErrorResult& aError);
  void SetScreenY(int32_t aScreenY,
                  mozilla::dom::CallerType aCallerType,
                  mozilla::ErrorResult& aError);
  int32_t GetOuterWidthOuter(mozilla::dom::CallerType aCallerType, mozilla::ErrorResult& aError);
  int32_t GetOuterWidth(mozilla::dom::CallerType aCallerType, mozilla::ErrorResult& aError);
  void SetOuterWidthOuter(int32_t aOuterWidth,
                          mozilla::dom::CallerType aCallerType,
                          mozilla::ErrorResult& aError);
  void SetOuterWidth(int32_t aOuterWidth,
                     mozilla::dom::CallerType aCallerType,
                     mozilla::ErrorResult& aError);
  int32_t GetOuterHeightOuter(mozilla::dom::CallerType aCallerType, mozilla::ErrorResult& aError);
  int32_t GetOuterHeight(mozilla::dom::CallerType aCallerType, mozilla::ErrorResult& aError);
  void SetOuterHeightOuter(int32_t aOuterHeight,
                           mozilla::dom::CallerType aCallerType,
                           mozilla::ErrorResult& aError);
  void SetOuterHeight(int32_t aOuterHeight,
                      mozilla::dom::CallerType aCallerType,
                      mozilla::ErrorResult& aError);

  // Array of idle observers that are notified of idle events.
  nsTObserverArray<IdleObserverHolder> mIdleObservers;

  // Idle timer used for function callbacks to notify idle observers.
  nsCOMPtr<nsITimer> mIdleTimer;

  // Idle fuzz time added to idle timer callbacks.
  uint32_t mIdleFuzzFactor;

  // Index in mArrayIdleObservers
  // Next idle observer to notify user idle status
  int32_t mIdleCallbackIndex;

  // If false then the topic is "active"
  // If true then the topic is "idle"
  bool mCurrentlyIdle;

  // Set to true when a fuzz time needs to be applied
  // to active notifications to the idle observer.
  bool mAddActiveEventFuzzTime;

  nsCOMPtr<nsIIdleService> mIdleService;

  RefPtr<mozilla::dom::WakeLock> mWakeLock;

  static bool sIdleObserversAPIFuzzTimeDisabled;

  friend class HashchangeCallback;
  friend class mozilla::dom::BarProp;

  // Object Management
  virtual ~nsGlobalWindow();
  void DropOuterWindowDocs();
  void CleanUp();
  void ClearControllers();
  // Outer windows only.
  void FinalClose();

  inline void MaybeClearInnerWindow(nsGlobalWindow* aExpectedInner)
  {
    if (mInnerWindow == aExpectedInner->AsInner()) {
      mInnerWindow = nullptr;
    }
  }

  void FreeInnerObjects();
  nsGlobalWindow* CallerInnerWindow();

  // Only to be called on an inner window.
  // aDocument must not be null.
  void InnerSetNewDocument(JSContext* aCx, nsIDocument* aDocument);

  // Inner windows only.
  nsresult DefineArgumentsProperty(nsIArray* aArguments);

  // Get the parent, returns null if this is a toplevel window
  nsPIDOMWindowOuter* GetParentInternal();

public:
  // popup tracking
  bool IsPopupSpamWindow()
  {
    if (IsInnerWindow() && !mOuterWindow) {
      return false;
    }

    return GetOuterWindowInternal()->mIsPopupSpam;
  }

  // Outer windows only.
  void SetIsPopupSpamWindow(bool aIsPopupSpam);

protected:
  // Window Control Functions

  // Outer windows only.
  virtual nsresult OpenNoNavigate(const nsAString& aUrl,
                                  const nsAString& aName,
                                  const nsAString& aOptions,
                                  nsPIDOMWindowOuter** _retval) override;

private:
  /**
   * @param aUrl the URL we intend to load into the window.  If aNavigate is
   *        true, we'll actually load this URL into the window. Otherwise,
   *        aUrl is advisory; OpenInternal will not load the URL into the
   *        new window.
   *
   * @param aName the name to use for the new window
   *
   * @param aOptions the window options to use for the new window
   *
   * @param aDialog true when called from variants of OpenDialog.  If this is
   *        true, this method will skip popup blocking checks.  The aDialog
   *        argument is passed on to the window watcher.
   *
   * @param aCalledNoScript true when called via the [noscript] open()
   *        and openDialog() methods.  When this is true, we do NOT want to use
   *        the JS stack for things like caller determination.
   *
   * @param aDoJSFixups true when this is the content-accessible JS version of
   *        window opening.  When true, popups do not cause us to throw, we save
   *        the caller's principal in the new window for later consumption, and
   *        we make sure that there is a document in the newly-opened window.
   *        Note that this last will only be done if the newly-opened window is
   *        non-chrome.
   *
   * @param aNavigate true if we should navigate to the provided URL, false
   *        otherwise.  When aNavigate is false, we also skip our can-load
   *        security check, on the assumption that whoever *actually* loads this
   *        page will do their own security check.
   *
   * @param argv The arguments to pass to the new window.  The first
   *        three args, if present, will be aUrl, aName, and aOptions.  So this
   *        param only matters if there are more than 3 arguments.
   *
   * @param aExtraArgument Another way to pass arguments in.  This is mutually
   *        exclusive with the argv approach.
   *
   * @param aLoadInfo to be passed on along to the windowwatcher.
   *
   * @param aForceNoOpener if true, will act as if "noopener" were passed in
   *                       aOptions, but without affecting any other window
   *                       features.
   *
   * @param aReturn [out] The window that was opened, if any.  Will be null if
   *                      aForceNoOpener is true of if aOptions contains
   *                      "noopener".
   *
   * Outer windows only.
   */
  nsresult OpenInternal(const nsAString& aUrl,
                        const nsAString& aName,
                        const nsAString& aOptions,
                        bool aDialog,
                        bool aContentModal,
                        bool aCalledNoScript,
                        bool aDoJSFixups,
                        bool aNavigate,
                        nsIArray* argv,
                        nsISupports* aExtraArgument,
                        nsIDocShellLoadInfo* aLoadInfo,
                        bool aForceNoOpener,
                        nsPIDOMWindowOuter** aReturn);

  template<typename Method>
  void CallOnChildren(Method aMethod);

  void FreezeInternal();
  void ThawInternal();

public:
  // Timeout Functions
  // |interval| is in milliseconds.
  int32_t SetTimeoutOrInterval(JSContext* aCx,
                               mozilla::dom::Function& aFunction,
                               int32_t aTimeout,
                               const mozilla::dom::Sequence<JS::Value>& aArguments,
                               bool aIsInterval,
                               mozilla::ErrorResult& aError);
  int32_t SetTimeoutOrInterval(JSContext* aCx,
                               const nsAString& aHandler,
                               int32_t aTimeout,
                               bool aIsInterval,
                               mozilla::ErrorResult& aError);

  // Return true if |aTimeout| was cleared while its handler ran.
  bool RunTimeoutHandler(mozilla::dom::Timeout* aTimeout, nsIScriptContext* aScx);

  // Helper Functions
  already_AddRefed<nsIDocShellTreeOwner> GetTreeOwner();
  already_AddRefed<nsIBaseWindow> GetTreeOwnerWindow();
  already_AddRefed<nsIWebBrowserChrome> GetWebBrowserChrome();
  nsresult SecurityCheckURL(const char* aURL);
  bool IsPrivateBrowsing();

  bool PopupWhitelisted();
  PopupControlState RevisePopupAbuseLevel(PopupControlState);
  void FireAbuseEvents(const nsAString& aPopupURL,
                       const nsAString& aPopupWindowName,
                       const nsAString& aPopupWindowFeatures);
  void FireOfflineStatusEventIfChanged();

  bool GetIsPrerendered();

private:
  void ReportLargeAllocStatus();

public:
  // Inner windows only.
  nsresult ScheduleNextIdleObserverCallback();
  uint32_t GetFuzzTimeMS();
  nsresult ScheduleActiveTimerCallback();
  uint32_t FindInsertionIndex(IdleObserverHolder* aIdleObserver);
  virtual nsresult RegisterIdleObserver(nsIIdleObserver* aIdleObserverPtr) override;
  nsresult FindIndexOfElementToRemove(nsIIdleObserver* aIdleObserver,
                                      int32_t* aRemoveElementIndex);
  virtual nsresult UnregisterIdleObserver(nsIIdleObserver* aIdleObserverPtr) override;

  // Inner windows only.
  nsresult FireHashchange(const nsAString& aOldURL, const nsAString& aNewURL);

  void FlushPendingNotifications(mozilla::FlushType aType);

  // Outer windows only.
  void EnsureReflowFlushAndPaint();
  void CheckSecurityWidthAndHeight(int32_t* width,
                                   int32_t* height,
                                   mozilla::dom::CallerType aCallerType);
  void CheckSecurityLeftAndTop(int32_t* left, int32_t* top, mozilla::dom::CallerType aCallerType);

  // Outer windows only.
  // Arguments to this function should have values in app units
  void SetCSSViewportWidthAndHeight(nscoord width, nscoord height);
  // Arguments to this function should have values in device pixels
  nsresult SetDocShellWidthAndHeight(int32_t width, int32_t height);

  static bool CanSetProperty(const char* aPrefName);

  static void MakeScriptDialogTitle(nsAString& aOutTitle, nsIPrincipal* aSubjectPrincipal);

  // Outer windows only.
  bool CanMoveResizeWindows(mozilla::dom::CallerType aCallerType);

  // If aDoFlush is true, we'll flush our own layout; otherwise we'll try to
  // just flush our parent and only flush ourselves if we think we need to.
  // Outer windows only.
  mozilla::CSSIntPoint GetScrollXY(bool aDoFlush);

  int32_t GetScrollBoundaryOuter(mozilla::Side aSide);

  // Outer windows only.
  nsresult GetInnerSize(mozilla::CSSIntSize& aSize);
  nsIntSize GetOuterSize(mozilla::dom::CallerType aCallerType, mozilla::ErrorResult& aError);
  void SetOuterSize(int32_t aLengthCSSPixels,
                    bool aIsWidth,
                    mozilla::dom::CallerType aCallerType,
                    mozilla::ErrorResult& aError);
  nsRect GetInnerScreenRect();

  void ScrollTo(const mozilla::CSSIntPoint& aScroll, const mozilla::dom::ScrollOptions& aOptions);

  bool IsFrame() { return GetParentInternal() != nullptr; }

  // Outer windows only.
  // If aLookForCallerOnJSStack is true, this method will look at the JS stack
  // to determine who the caller is.  If it's false, it'll use |this| as the
  // caller.
  bool WindowExists(const nsAString& aName, bool aForceNoOpener, bool aLookForCallerOnJSStack);

  already_AddRefed<nsIWidget> GetMainWidget();
  nsIWidget* GetNearestWidget() const;

  bool IsInModalState();

  // Convenience functions for the many methods that need to scale
  // from device to CSS pixels or vice versa.  Note: if a presentation
  // context is not available, they will assume a 1:1 ratio.
  int32_t DevToCSSIntPixels(int32_t px);
  int32_t CSSToDevIntPixels(int32_t px);
  nsIntSize DevToCSSIntPixels(nsIntSize px);
  nsIntSize CSSToDevIntPixels(nsIntSize px);

  virtual void SetFocusedNode(nsIContent* aNode,
                              uint32_t aFocusMethod = 0,
                              bool aNeedsFocus = false) override;

  virtual uint32_t GetFocusMethod() override;

  virtual bool ShouldShowFocusRing() override;

  virtual void SetKeyboardIndicators(UIStateChangeType aShowAccelerators,
                                     UIStateChangeType aShowFocusRings) override;

  // Inner windows only.
  void UpdateCanvasFocus(bool aFocusChanged, nsIContent* aNewContent);

public:
  virtual already_AddRefed<nsPIWindowRoot> GetTopWindowRoot() override;

protected:
  static void NotifyDOMWindowDestroyed(nsGlobalWindow* aWindow);
  void NotifyWindowIDDestroyed(const char* aTopic);

  static void NotifyDOMWindowFrozen(nsGlobalWindow* aWindow);
  static void NotifyDOMWindowThawed(nsGlobalWindow* aWindow);

  void ClearStatus();

  virtual void UpdateParentTarget() override;

  void InitializeShowFocusRings();

  // Clear the document-dependent slots on our JS wrapper.  Inner windows only.
  void ClearDocumentDependentSlots(JSContext* aCx);

  // Inner windows only.
  already_AddRefed<mozilla::dom::StorageEvent> CloneStorageEvent(
    const nsAString& aType,
    const RefPtr<mozilla::dom::StorageEvent>& aEvent,
    mozilla::ErrorResult& aRv);

public:
  // Outer windows only.
  nsDOMWindowList* GetWindowList();

protected:
  // Helper for getComputedStyle and getDefaultComputedStyle
  already_AddRefed<nsICSSDeclaration> GetComputedStyleHelperOuter(mozilla::dom::Element& aElt,
                                                                  const nsAString& aPseudoElt,
                                                                  bool aDefaultStylesOnly);
  already_AddRefed<nsICSSDeclaration> GetComputedStyleHelper(mozilla::dom::Element& aElt,
                                                             const nsAString& aPseudoElt,
                                                             bool aDefaultStylesOnly,
                                                             mozilla::ErrorResult& aError);
  nsresult GetComputedStyleHelper(nsIDOMElement* aElt,
                                  const nsAString& aPseudoElt,
                                  bool aDefaultStylesOnly,
                                  nsIDOMCSSStyleDeclaration** aReturn);

  // Outer windows only.
  void PreloadLocalStorage();

  // Returns CSS pixels based on primary screen.  Outer windows only.
  mozilla::CSSIntPoint GetScreenXY(mozilla::dom::CallerType aCallerType,
                                   mozilla::ErrorResult& aError);

  nsGlobalWindow* InnerForSetTimeoutOrInterval(mozilla::ErrorResult& aError);

  void PostMessageMozOuter(JSContext* aCx,
                           JS::Handle<JS::Value> aMessage,
                           const nsAString& aTargetOrigin,
                           JS::Handle<JS::Value> aTransfer,
                           nsIPrincipal& aSubjectPrincipal,
                           mozilla::ErrorResult& aError);
  void PostMessageMoz(JSContext* aCx,
                      JS::Handle<JS::Value> aMessage,
                      const nsAString& aTargetOrigin,
                      JS::Handle<JS::Value> aTransfer,
                      nsIPrincipal& aSubjectPrincipal,
                      mozilla::ErrorResult& aError);

  already_AddRefed<nsIVariant> ShowModalDialogOuter(const nsAString& aUrl,
                                                    nsIVariant* aArgument,
                                                    const nsAString& aOptions,
                                                    nsIPrincipal& aSubjectPrincipal,
                                                    mozilla::ErrorResult& aError);

  already_AddRefed<nsIVariant> ShowModalDialog(const nsAString& aUrl,
                                               nsIVariant* aArgument,
                                               const nsAString& aOptions,
                                               nsIPrincipal& aSubjectPrincipal,
                                               mozilla::ErrorResult& aError);

  // Ask the user if further dialogs should be blocked, if dialogs are currently
  // being abused. This is used in the cases where we have no modifiable UI to
  // show, in that case we show a separate dialog to ask this question.
  bool ConfirmDialogIfNeeded();

  // Helper called after moving/resizing, to update docShell's presContext
  // if we have caused a resolution change by moving across monitors.
  void CheckForDPIChange();

private:
  // Fire the JS engine's onNewGlobalObject hook.  Only used on inner windows.
  void FireOnNewGlobalObject();

  void DisconnectEventTargetObjects();

  enum class SecureContextFlags
  {
    eDefault,
    eIgnoreOpener
  };
  // Called only on outer windows to compute the value that will be returned by
  // IsSecureContext() for the inner window that corresponds to aDocument.
  bool ComputeIsSecureContext(nsIDocument* aDocument,
                              SecureContextFlags aFlags = SecureContextFlags::eDefault);

  // nsPIDOMWindow<T> should be able to see these helper methods.
  friend class nsPIDOMWindow<mozIDOMWindowProxy>;
  friend class nsPIDOMWindow<mozIDOMWindow>;
  friend class nsPIDOMWindow<nsISupports>;

  mozilla::dom::TabGroup* TabGroupInner();
  mozilla::dom::TabGroup* TabGroupOuter();

  bool IsBackgroundInternal() const;

public:
  // Dispatch a runnable related to the global.
  virtual nsresult Dispatch(const char* aName,
                            mozilla::TaskCategory aCategory,
                            already_AddRefed<nsIRunnable>&& aRunnable) override;

  virtual nsIEventTarget* EventTargetFor(mozilla::TaskCategory aCategory) const override;

  virtual mozilla::AbstractThread* AbstractMainThreadFor(mozilla::TaskCategory aCategory) override;

  void DisableIdleCallbackRequests();
  uint32_t IdleRequestHandle() const { return mIdleRequestCallbackCounter; }
  nsresult RunIdleRequest(mozilla::dom::IdleRequest* aRequest,
                          DOMHighResTimeStamp aDeadline,
                          bool aDidTimeout);
  nsresult ExecuteIdleRequest(TimeStamp aDeadline);
  void ScheduleIdleRequestDispatch();
  void SuspendIdleRequests();
  void ResumeIdleRequests();

  typedef mozilla::LinkedList<mozilla::dom::IdleRequest> IdleRequests;
  void InsertIdleCallback(mozilla::dom::IdleRequest* aRequest);

  void RemoveIdleCallback(mozilla::dom::IdleRequest* aRequest);

protected:
  // These members are only used on outer window objects. Make sure
  // you never set any of these on an inner object!
  bool mFullScreen : 1;
  bool mFullscreenMode : 1;
  bool mIsClosed : 1;
  bool mInClose : 1;
  // mHavePendingClose means we've got a termination function set to
  // close us when the JS stops executing or that we have a close
  // event posted.  If this is set, just ignore window.close() calls.
  bool mHavePendingClose : 1;
  bool mHadOriginalOpener : 1;
  bool mOriginalOpenerWasSecureContext : 1;
  bool mIsSecureContextIfOpenerIgnored : 1;
  bool mIsPopupSpam : 1;

  // Indicates whether scripts are allowed to close this window.
  bool mBlockScriptedClosingFlag : 1;

  // Window offline status. Checked to see if we need to fire offline event
  bool mWasOffline : 1;

  // Represents whether the inner window's page has had a slow script notice.
  // Only used by inner windows; will always be false for outer windows.
  // This is used to implement Telemetry measures such as SLOW_SCRIPT_PAGE_COUNT.
  bool mHasHadSlowScript : 1;

  // Track what sorts of events we need to fire when thawed
  bool mNotifyIdleObserversIdleOnThaw : 1;
  bool mNotifyIdleObserversActiveOnThaw : 1;

  // Indicates whether we're in the middle of creating an initializing
  // a new inner window object.
  bool mCreatingInnerWindow : 1;

  // Fast way to tell if this is a chrome window (without having to QI).
  bool mIsChrome : 1;

  // Hack to indicate whether a chrome window needs its message manager
  // to be disconnected, since clean up code is shared in the global
  // window superclass.
  bool mCleanMessageManager : 1;

  // Indicates that the current document has never received a document focus
  // event.
  bool mNeedsFocus : 1;
  bool mHasFocus : 1;

  // when true, show focus rings for the current focused content only.
  // This will be reset when another element is focused
  bool mShowFocusRingForContent : 1;

  // true if tab navigation has occurred for this window. Focus rings
  // should be displayed.
  bool mFocusByKeyOccurred : 1;

  // Inner windows only.
  // Indicates whether this window wants gamepad input events
  bool mHasGamepad : 1;

  // Inner windows only.
  // Indicates whether this window wants VR events
  bool mHasVREvents : 1;
  nsCheapSet<nsUint32HashKey> mGamepadIndexSet;
  nsRefPtrHashtable<nsUint32HashKey, mozilla::dom::Gamepad> mGamepads;
  bool mHasSeenGamepadInput;

  // whether we've sent the destroy notification for our window id
  bool mNotifiedIDDestroyed : 1;
  // whether scripts may close the window,
  // even if "dom.allow_scripts_to_close_windows" is false.
  bool mAllowScriptsToClose : 1;

  bool mTopLevelOuterContentWindow : 1;

  nsCOMPtr<nsIScriptContext> mContext;
  nsWeakPtr mOpener;
  nsCOMPtr<nsIControllers> mControllers;

  // For |window.arguments|, via |openDialog|.
  nsCOMPtr<nsIArray> mArguments;

  // For |window.dialogArguments|, via |showModalDialog|.
  RefPtr<DialogValueHolder> mDialogArguments;

  // Only used in the outer.
  RefPtr<DialogValueHolder> mReturnValue;

  RefPtr<mozilla::dom::Navigator> mNavigator;
  RefPtr<nsScreen> mScreen;
  RefPtr<nsDOMWindowList> mFrames;
  // All BarProps are inner window only.
  RefPtr<mozilla::dom::BarProp> mMenubar;
  RefPtr<mozilla::dom::BarProp> mToolbar;
  RefPtr<mozilla::dom::BarProp> mLocationbar;
  RefPtr<mozilla::dom::BarProp> mPersonalbar;
  RefPtr<mozilla::dom::BarProp> mStatusbar;
  RefPtr<mozilla::dom::BarProp> mScrollbars;
  RefPtr<nsDOMWindowUtils> mWindowUtils;
  nsString mStatus;
  nsString mDefaultStatus;
  RefPtr<nsGlobalWindowObserver> mObserver; // Inner windows only.
  RefPtr<mozilla::dom::Crypto> mCrypto;
  RefPtr<mozilla::dom::U2F> mU2F;
  RefPtr<mozilla::dom::cache::CacheStorage> mCacheStorage;
  RefPtr<mozilla::dom::Console> mConsole;
  RefPtr<mozilla::dom::Worklet> mAudioWorklet;
  RefPtr<mozilla::dom::Worklet> mPaintWorklet;
  // We need to store an nsISupports pointer to this object because the
  // mozilla::dom::External class doesn't exist on b2g and using the type
  // forward declared here means that ~nsGlobalWindow wouldn't compile because
  // it wouldn't see the ~External function's declaration.
  nsCOMPtr<nsISupports> mExternal;

  RefPtr<mozilla::dom::MozSelfSupport> mMozSelfSupport;

  RefPtr<mozilla::dom::Storage> mLocalStorage;
  RefPtr<mozilla::dom::Storage> mSessionStorage;

  // These member variable are used only on inner windows.
  RefPtr<mozilla::EventListenerManager> mListenerManager;
  RefPtr<mozilla::dom::Location> mLocation;
  RefPtr<nsHistory> mHistory;
  RefPtr<mozilla::dom::CustomElementRegistry> mCustomElements;

  // These member variables are used on both inner and the outer windows.
  nsCOMPtr<nsIPrincipal> mDocumentPrincipal;

  uint32_t mSuspendDepth;
  uint32_t mFreezeDepth;

  // the method that was used to focus mFocusedNode
  uint32_t mFocusMethod;

  uint32_t mSerial;

  // The current idle request callback handle
  uint32_t mIdleRequestCallbackCounter;
  IdleRequests mIdleRequestCallbacks;
  RefPtr<IdleRequestExecutor> mIdleRequestExecutor;

#ifdef DEBUG
  bool mSetOpenerWindowCalled;
  nsCOMPtr<nsIURI> mLastOpenedURI;
#endif

#ifdef MOZ_B2G
  bool mNetworkUploadObserverEnabled;
  bool mNetworkDownloadObserverEnabled;
#endif // MOZ_B2G

  bool mCleanedUp;

  nsCOMPtr<nsIDOMOfflineResourceList> mApplicationCache;

  using XBLPrototypeHandlerTable =
    nsJSThingHashtable<nsPtrHashKey<nsXBLPrototypeHandler>, JSObject*>;
  nsAutoPtr<XBLPrototypeHandlerTable> mCachedXBLPrototypeHandlers;

  // mSuspendedDoc is only set on outer windows. It's useful when we get matched
  // EnterModalState/LeaveModalState calls, in which case the outer window is
  // responsible for unsuspending events on the document. If we don't (for
  // example, if the outer window is closed before the LeaveModalState call),
  // then the inner window whose mDoc is our mSuspendedDoc is responsible for
  // unsuspending it.
  nsCOMPtr<nsIDocument> mSuspendedDoc;

  RefPtr<mozilla::dom::IDBFactory> mIndexedDB;

  // This counts the number of windows that have been opened in rapid succession
  // (i.e. within dom.successive_dialog_time_limit of each other). It is reset
  // to 0 once a dialog is opened after dom.successive_dialog_time_limit seconds
  // have elapsed without any other dialogs.
  uint32_t mDialogAbuseCount;

  // This holds the time when the last modal dialog was shown. If more than
  // MAX_DIALOG_LIMIT dialogs are shown within the time span defined by
  // dom.successive_dialog_time_limit, we show a checkbox or confirmation prompt
  // to allow disabling of further dialogs from this window.
  TimeStamp mLastDialogQuitTime;

  // This flag keeps track of whether dialogs are
  // currently enabled on this window.
  bool mAreDialogsEnabled;

  nsTHashtable<nsPtrHashKey<mozilla::DOMEventTargetHelper>> mEventTargetObjects;

  nsTArray<uint32_t> mEnabledSensors;

#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
  nsAutoPtr<mozilla::dom::WindowOrientationObserver> mOrientationChangeObserver;
#endif

#ifdef MOZ_WEBSPEECH
  // mSpeechSynthesis is only used on inner windows.
  RefPtr<mozilla::dom::SpeechSynthesis> mSpeechSynthesis;
#endif

#ifdef DEBUG
  // This member is used in the debug only assertions in TabGroup()
  // to catch cyclic parent/opener trees and not overflow the stack.
  bool mIsValidatingTabGroup;
#endif

  // This is the CC generation the last time we called CanSkip.
  uint32_t mCanSkipCCGeneration;

  // The VR Displays for this window
  nsTArray<RefPtr<mozilla::dom::VRDisplay>> mVRDisplays;

  RefPtr<mozilla::dom::VREventObserver> mVREventObserver;

  friend class nsDOMScriptableHelper;
  friend class nsDOMWindowUtils;
  friend class mozilla::dom::PostMessageEvent;
  friend class DesktopNotification;
  friend class mozilla::dom::TimeoutManager;
  friend class IdleRequestExecutor;

  static WindowByIdTable* sWindowsById;
  static bool sWarnedAboutWindowInternal;
};

inline nsISupports*
ToSupports(nsGlobalWindow* p)
{
  return static_cast<nsIDOMEventTarget*>(p);
}

inline nsISupports*
ToCanonicalSupports(nsGlobalWindow* p)
{
  return static_cast<nsIDOMEventTarget*>(p);
}

/*
 * nsGlobalChromeWindow inherits from nsGlobalWindow. It is the global
 * object created for a Chrome Window only.
 */
class nsGlobalChromeWindow : public nsGlobalWindow, public nsIDOMChromeWindow
{
public:
  // nsISupports
  NS_DECL_ISUPPORTS_INHERITED

  // nsIDOMChromeWindow interface
  NS_DECL_NSIDOMCHROMEWINDOW

  static already_AddRefed<nsGlobalChromeWindow> Create(nsGlobalWindow* aOuterWindow);

  void DisconnectAndClearGroupMessageManagers()
  {
    for (auto iter = mGroupMessageManagers.Iter(); !iter.Done(); iter.Next()) {
      nsIMessageBroadcaster* mm = iter.UserData();
      if (mm) {
        static_cast<nsFrameMessageManager*>(mm)->Disconnect();
      }
    }
    mGroupMessageManagers.Clear();
  }

protected:
  explicit nsGlobalChromeWindow(nsGlobalWindow* aOuterWindow)
    : nsGlobalWindow(aOuterWindow)
    , mGroupMessageManagers(1)
  {
    mIsChrome = true;
    mCleanMessageManager = true;
  }

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

    DisconnectAndClearGroupMessageManagers();

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

    mCleanMessageManager = false;
  }

public:
  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsGlobalChromeWindow, nsGlobalWindow)

  using nsGlobalWindow::GetBrowserDOMWindow;
  using nsGlobalWindow::SetBrowserDOMWindow;
  using nsGlobalWindow::GetAttention;
  using nsGlobalWindow::GetAttentionWithCycleCount;
  using nsGlobalWindow::SetCursor;
  using nsGlobalWindow::Maximize;
  using nsGlobalWindow::Minimize;
  using nsGlobalWindow::Restore;
  using nsGlobalWindow::NotifyDefaultButtonLoaded;
  using nsGlobalWindow::GetMessageManager;
  using nsGlobalWindow::GetGroupMessageManager;
  using nsGlobalWindow::BeginWindowMove;

  nsCOMPtr<nsIBrowserDOMWindow> mBrowserDOMWindow;
  nsCOMPtr<nsIMessageBroadcaster> mMessageManager;
  nsInterfaceHashtable<nsStringHashKey, nsIMessageBroadcaster> mGroupMessageManagers;
  // A weak pointer to the nsPresShell that we are doing fullscreen for.
  // The pointer being set indicates we've set the IsInFullscreenChange
  // flag on this pres shell.
  nsWeakPtr mFullscreenPresShell;
  nsCOMPtr<mozIDOMWindowProxy> mOpenerForInitialContentBrowser;
};

/*
 * nsGlobalModalWindow inherits from nsGlobalWindow. It is the global
 * object created for a modal content windows only (i.e. not modal
 * chrome dialogs).
 */
class nsGlobalModalWindow : public nsGlobalWindow, public nsIDOMModalContentWindow
{
public:
  NS_DECL_ISUPPORTS_INHERITED
  NS_DECL_NSIDOMMODALCONTENTWINDOW

  static already_AddRefed<nsGlobalModalWindow> Create(nsGlobalWindow* aOuterWindow);

protected:
  explicit nsGlobalModalWindow(nsGlobalWindow* aOuterWindow)
    : nsGlobalWindow(aOuterWindow)
  {
    mIsModalContentWindow = true;
  }

  ~nsGlobalModalWindow() {}
};

/* factory function */
inline already_AddRefed<nsGlobalWindow>
NS_NewScriptGlobalObject(bool aIsChrome, bool aIsModalContentWindow)
{
  RefPtr<nsGlobalWindow> global;

  if (aIsChrome) {
    global = nsGlobalChromeWindow::Create(nullptr);
  } else if (aIsModalContentWindow) {
    global = nsGlobalModalWindow::Create(nullptr);
  } else {
    global = nsGlobalWindow::Create(nullptr);
  }

  return global.forget();
}

#endif /* nsGlobalWindow_h___ */