Bug 1416384 - Part 9: Deduplicate more code when possible, r=smaug
authorNika Layzell <nika@thelayzells.com>
Wed, 15 Nov 2017 11:34:47 -0500
changeset 392037 7b2f3fa349b001af0dce735501014c72f0f512c7
parent 392036 476642ee328b1363bd6505ed6ab04e57aeb75bdf
child 392038 80cb926578e4adff98080702d96c2b47b98a20b3
push id32909
push usercbrindusan@mozilla.com
push dateWed, 15 Nov 2017 22:25:14 +0000
treeherdermozilla-central@f41930a869a8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1416384
milestone59.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1416384 - Part 9: Deduplicate more code when possible, r=smaug MozReview-Commit-ID: 1mzNDOFUNep
dom/base/nsGlobalWindowInner.cpp
dom/base/nsGlobalWindowInner.h
dom/base/nsGlobalWindowOuter.cpp
dom/base/nsGlobalWindowOuter.h
dom/base/nsPIDOMWindow.h
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -1403,54 +1403,34 @@ nsGlobalWindowInner::IsBlackForCC(bool a
 
 //*****************************************************************************
 // nsGlobalWindowInner::nsIScriptGlobalObject
 //*****************************************************************************
 
 nsresult
 nsGlobalWindowInner::EnsureScriptEnvironment()
 {
+  // NOTE: We can't use FORWARD_TO_OUTER here because we don't want to fail if
+  // we're called on an inactive inner window.
   nsGlobalWindowOuter* outer = GetOuterWindowInternal();
   if (!outer) {
     NS_WARNING("No outer window available!");
     return NS_ERROR_FAILURE;
   }
-
-  if (outer->GetWrapperPreserveColor()) {
-    return NS_OK;
-  }
-
-  NS_ASSERTION(!outer->GetCurrentInnerWindowInternal(),
-               "No cached wrapper, but we have an inner window?");
-
-  // If this window is a [i]frame, don't bother GC'ing when the frame's context
-  // is destroyed since a GC will happen when the frameset or host document is
-  // destroyed anyway.
-  nsCOMPtr<nsIScriptContext> context = new nsJSContext(!IsFrame(), outer);
-
-  NS_ASSERTION(!outer->mContext, "Will overwrite mContext!");
-
-  // should probably assert the context is clean???
-  context->WillInitializeContext();
-
-  nsresult rv = context->InitContext();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  outer->mContext = context;
-  return NS_OK;
+  return outer->EnsureScriptEnvironment();
 }
 
 nsIScriptContext *
 nsGlobalWindowInner::GetScriptContext()
 {
   nsGlobalWindowOuter* outer = GetOuterWindowInternal();
   if (!outer) {
     return nullptr;
   }
-  return outer->mContext;
+  return outer->GetScriptContext();
 }
 
 JSObject *
 nsGlobalWindowInner::GetGlobalJSObject()
 {
   return FastGetGlobalJSObject();
 }
 
@@ -1544,16 +1524,20 @@ nsGlobalWindowInner::SetOpenerWindow(nsP
                                      bool aOriginalOpener)
 {
   FORWARD_TO_OUTER_VOID(SetOpenerWindow, (aOpener, aOriginalOpener));
 }
 
 void
 nsGlobalWindowInner::UpdateParentTarget()
 {
+  // NOTE: This method is identical to
+  // nsGlobalWindowOuter::UpdateParentTarget(). IF YOU UPDATE THIS METHOD,
+  // UPDATE THE OTHER ONE TOO!
+
   // Try to get our frame element's tab child global (its in-process message
   // manager).  If that fails, fall back to the chrome event handler's tab
   // child global, and if it doesn't have one, just use the chrome event
   // handler itself.
 
   nsCOMPtr<Element> frameElement = GetOuterWindow()->GetFrameElementInternal();
   nsCOMPtr<EventTarget> eventTarget =
     TryGetTabChildGlobalAsEventTarget(frameElement);
@@ -1667,43 +1651,23 @@ nsGlobalWindowInner::DialogsAreBeingAbus
   mDialogAbuseCount = 0;
 
   return false;
 }
 
 void
 nsGlobalWindowInner::DisableDialogs()
 {
-  nsGlobalWindowOuter *topWindowOuter = GetScriptableTopInternal();
-  if (!topWindowOuter) {
-    NS_ERROR("DisableDialogs() called without a top window?");
-    return;
-  }
-
-  nsGlobalWindowInner* topWindow = topWindowOuter->GetCurrentInnerWindowInternal();
-  // TODO: Warn if no top window?
-  if (topWindow) {
-    topWindow->mAreDialogsEnabled = false;
-  }
+  FORWARD_TO_OUTER_VOID(DisableDialogs, ());
 }
 
 void
 nsGlobalWindowInner::EnableDialogs()
 {
-  nsGlobalWindowOuter *topWindowOuter = GetScriptableTopInternal();
-  if (!topWindowOuter) {
-    NS_ERROR("EnableDialogs() called without a top window?");
-    return;
-  }
-
-  // TODO: Warn if no top window?
-  nsGlobalWindowInner* topWindow = topWindowOuter->GetCurrentInnerWindowInternal();
-  if (topWindow) {
-    topWindow->mAreDialogsEnabled = true;
-  }
+  FORWARD_TO_OUTER_VOID(EnableDialogs, ());
 }
 
 nsresult
 nsGlobalWindowInner::PostHandleEvent(EventChainPostVisitor& aVisitor)
 {
   NS_PRECONDITION(IsInnerWindow(), "PostHandleEvent is used on outer window!?");
 
   // Return early if there is nothing to do.
@@ -3138,24 +3102,20 @@ already_AddRefed<nsPIDOMWindowOuter>
 nsGlobalWindowInner::GetTop(mozilla::ErrorResult& aError)
 {
   FORWARD_TO_OUTER_OR_THROW(GetTopOuter, (), aError, nullptr);
 }
 
 nsPIDOMWindowOuter*
 nsGlobalWindowInner::GetChildWindow(const nsAString& aName)
 {
-  nsCOMPtr<nsIDocShell> docShell(GetDocShell());
-  NS_ENSURE_TRUE(docShell, nullptr);
-
-  nsCOMPtr<nsIDocShellTreeItem> child;
-  docShell->FindChildWithName(aName, false, true, nullptr, nullptr,
-                              getter_AddRefs(child));
-
-  return child ? child->GetWindow() : nullptr;
+  if (GetOuterWindowInternal()) {
+    return GetOuterWindowInternal()->GetChildWindow(aName);
+  }
+  return nullptr;
 }
 
 bool
 nsGlobalWindowInner::DispatchCustomEvent(const nsAString& aEventName)
 {
   MOZ_CRASH("Virtual outer window only function");
 }
 
@@ -3172,23 +3132,20 @@ already_AddRefed<nsIWidget>
 nsGlobalWindowInner::GetMainWidget()
 {
   FORWARD_TO_OUTER(GetMainWidget, (), nullptr);
 }
 
 nsIWidget*
 nsGlobalWindowInner::GetNearestWidget() const
 {
-  nsIDocShell* docShell = GetDocShell();
-  NS_ENSURE_TRUE(docShell, nullptr);
-  nsCOMPtr<nsIPresShell> presShell = docShell->GetPresShell();
-  NS_ENSURE_TRUE(presShell, nullptr);
-  nsIFrame* rootFrame = presShell->GetRootFrame();
-  NS_ENSURE_TRUE(rootFrame, nullptr);
-  return rootFrame->GetView()->GetNearestWidget(nullptr);
+  if (GetOuterWindowInternal()) {
+    return GetOuterWindowInternal()->GetNearestWidget();
+  }
+  return nullptr;
 }
 
 void
 nsGlobalWindowInner::SetFullScreen(bool aFullScreen, mozilla::ErrorResult& aError)
 {
   FORWARD_TO_OUTER_OR_THROW(SetFullScreenOuter, (aFullScreen, aError), aError, /* void */);
 }
 
@@ -3662,30 +3619,16 @@ void
 nsGlobalWindowInner::FirePopupBlockedEvent(nsIDocument* aDoc,
                                            nsIURI* aPopupURI,
                                            const nsAString& aPopupWindowName,
                                            const nsAString& aPopupWindowFeatures)
 {
   MOZ_CRASH("Virtual outer window only function");
 }
 
-// static
-bool
-nsGlobalWindowInner::CanSetProperty(const char *aPrefName)
-{
-  // Chrome can set any property.
-  if (nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
-    return true;
-  }
-
-  // If the pref is set to true, we can not set the property
-  // and vice versa.
-  return !Preferences::GetBool(aPrefName, true);
-}
-
 already_AddRefed<nsPIDOMWindowOuter>
 nsGlobalWindowInner::Open(const nsAString& aUrl, const nsAString& aName,
                           const nsAString& aOptions, ErrorResult& aError)
 {
   FORWARD_TO_OUTER_OR_THROW(OpenOuter, (aUrl, aName, aOptions, aError), aError,
                             nullptr);
 }
 
@@ -3844,25 +3787,17 @@ void
 nsGlobalWindowInner::LeaveModalState()
 {
   MOZ_CRASH("Virtual outer window only function");
 }
 
 bool
 nsGlobalWindowInner::IsInModalState()
 {
-  nsGlobalWindowOuter *topWin = GetScriptableTopInternal();
-
-  if (!topWin) {
-    // IsInModalState() getting called w/o a reachable top window is a bit
-    // iffy, but valid enough not to make noise about it.  See bug 404828
-    return false;
-  }
-
-  return topWin->mModalStateDepth != 0;
+  FORWARD_TO_OUTER(IsInModalState, (), false);
 }
 
 // static
 void
 nsGlobalWindowInner::NotifyDOMWindowDestroyed(nsGlobalWindowInner* aWindow)
 {
   nsCOMPtr<nsIObserverService> observerService =
     services::GetObserverService();
@@ -4089,47 +4024,19 @@ nsGlobalWindowInner::ConvertDialogOption
   }
 }
 
 nsresult
 nsGlobalWindowInner::UpdateCommands(const nsAString& anAction,
                                     nsISelection* aSel,
                                     int16_t aReason)
 {
-  // If this is a child process, redirect to the parent process.
-  if (nsIDocShell* docShell = GetDocShell()) {
-    if (nsCOMPtr<nsITabChild> child = docShell->GetTabChild()) {
-      nsCOMPtr<nsPIWindowRoot> root = GetTopWindowRoot();
-      if (root) {
-        nsContentUtils::AddScriptRunner(
-          new ChildCommandDispatcher(root, child, anAction));
-      }
-      return NS_OK;
-    }
-  }
-
-  nsPIDOMWindowOuter *rootWindow = GetPrivateRoot();
-  if (!rootWindow)
-    return NS_OK;
-
-  nsCOMPtr<nsIDOMXULDocument> xulDoc =
-    do_QueryInterface(rootWindow->GetExtantDoc());
-  // See if we contain a XUL document.
-  // selectionchange action is only used for mozbrowser, not for XUL. So we bypass
-  // XUL command dispatch if anAction is "selectionchange".
-  if (xulDoc && !anAction.EqualsLiteral("selectionchange")) {
-    // Retrieve the command dispatcher and call updateCommands on it.
-    nsCOMPtr<nsIDOMXULCommandDispatcher> xulCommandDispatcher;
-    xulDoc->GetCommandDispatcher(getter_AddRefs(xulCommandDispatcher));
-    if (xulCommandDispatcher) {
-      nsContentUtils::AddScriptRunner(new CommandDispatcher(xulCommandDispatcher,
-                                                            anAction));
-    }
-  }
-
+  if (GetOuterWindowInternal()) {
+    return GetOuterWindowInternal()->UpdateCommands(anAction, aSel, aReason);
+  }
   return NS_OK;
 }
 
 Selection*
 nsGlobalWindowInner::GetSelection(ErrorResult& aError)
 {
   FORWARD_TO_OUTER_OR_THROW(GetSelectionOuter, (), aError, nullptr);
 }
@@ -4309,24 +4216,17 @@ nsGlobalWindowInner::GetExistingListener
 {
   return mListenerManager;
 }
 
 nsIScriptContext*
 nsGlobalWindowInner::GetContextForEventHandlers(nsresult* aRv)
 {
   *aRv = NS_ERROR_UNEXPECTED;
-  NS_ENSURE_TRUE(IsCurrentInnerWindow(), nullptr);
-
-  nsIScriptContext* scx;
-  if ((scx = GetContext())) {
-    *aRv = NS_OK;
-    return scx;
-  }
-  return nullptr;
+  FORWARD_TO_OUTER(GetContextForEventHandlers, (aRv), nullptr);
 }
 
 //*****************************************************************************
 // nsGlobalWindowInner::nsPIDOMWindow
 //*****************************************************************************
 
 nsPIDOMWindowOuter*
 nsGlobalWindowInner::GetPrivateRoot()
@@ -4361,29 +4261,20 @@ void
 nsGlobalWindowInner::SetActive(bool aActive)
 {
   MOZ_CRASH("Virtual outer window only function");
 }
 
 bool
 nsGlobalWindowInner::IsTopLevelWindowActive()
 {
-   nsCOMPtr<nsIDocShellTreeItem> treeItem(GetDocShell());
-   if (!treeItem) {
-     return false;
-   }
-
-   nsCOMPtr<nsIDocShellTreeItem> rootItem;
-   treeItem->GetRootTreeItem(getter_AddRefs(rootItem));
-   if (!rootItem) {
-     return false;
-   }
-
-   nsCOMPtr<nsPIDOMWindowOuter> domWindow = rootItem->GetWindow();
-   return domWindow && domWindow->IsActive();
+  if (GetOuterWindowInternal()) {
+    return GetOuterWindowInternal()->IsTopLevelWindowActive();
+  }
+  return false;
 }
 
 void
 nsGlobalWindowInner::SetIsBackground(bool aIsBackground)
 {
   MOZ_CRASH("Virtual outer window only function");
 }
 
@@ -4998,79 +4889,24 @@ nsGlobalWindowInner::GetIndexedDB(ErrorR
 
 //*****************************************************************************
 // nsGlobalWindowInner::nsIInterfaceRequestor
 //*****************************************************************************
 
 NS_IMETHODIMP
 nsGlobalWindowInner::GetInterface(const nsIID & aIID, void **aSink)
 {
-  NS_ENSURE_ARG_POINTER(aSink);
-  *aSink = nullptr;
-
-  if (aIID.Equals(NS_GET_IID(nsIDocCharset))) {
-    nsGlobalWindowOuter* outer = GetOuterWindowInternal();
-    NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
-
-    NS_WARNING("Using deprecated nsIDocCharset: use nsIDocShell.GetCharset() instead ");
-    nsCOMPtr<nsIDocCharset> docCharset(do_QueryInterface(outer->mDocShell));
-    docCharset.forget(aSink);
-  }
-  else if (aIID.Equals(NS_GET_IID(nsIWebNavigation))) {
-    nsGlobalWindowOuter* outer = GetOuterWindowInternal();
-    NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
-
-    nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(outer->mDocShell));
-    webNav.forget(aSink);
-  }
-  else if (aIID.Equals(NS_GET_IID(nsIDocShell))) {
-    nsGlobalWindowOuter* outer = GetOuterWindowInternal();
-    NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
-
-    nsCOMPtr<nsIDocShell> docShell = outer->mDocShell;
-    docShell.forget(aSink);
-  }
-#ifdef NS_PRINTING
-  else if (aIID.Equals(NS_GET_IID(nsIWebBrowserPrint))) {
-    nsGlobalWindowOuter* outer = GetOuterWindowInternal();
-    NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
-
-    if (outer->mDocShell) {
-      nsCOMPtr<nsIContentViewer> viewer;
-      outer->mDocShell->GetContentViewer(getter_AddRefs(viewer));
-      if (viewer) {
-        nsCOMPtr<nsIWebBrowserPrint> webBrowserPrint(do_QueryInterface(viewer));
-        webBrowserPrint.forget(aSink);
-      }
-    }
-  }
-#endif
-  else if (aIID.Equals(NS_GET_IID(nsIDOMWindowUtils))) {
-    nsGlobalWindowOuter* outer = GetOuterWindowInternal();
-    NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
-
-    if (!mWindowUtils) {
-      mWindowUtils = new nsDOMWindowUtils(outer);
-    }
-
-    *aSink = mWindowUtils;
-    NS_ADDREF(((nsISupports *) *aSink));
-  }
-  else if (aIID.Equals(NS_GET_IID(nsILoadContext))) {
-    nsGlobalWindowOuter* outer = GetOuterWindowInternal();
-    NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
-
-    nsCOMPtr<nsILoadContext> loadContext(do_QueryInterface(outer->mDocShell));
-    loadContext.forget(aSink);
-  }
-  else {
+  nsGlobalWindowOuter* outer = GetOuterWindowInternal();
+  NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
+
+  nsresult rv = outer->GetInterfaceInternal(aIID, aSink);
+  if (rv == NS_ERROR_NO_INTERFACE) {
     return QueryInterface(aIID, aSink);
   }
-
-  return *aSink ? NS_OK : NS_ERROR_NO_INTERFACE;
+  return rv;
 }
 
 void
 nsGlobalWindowInner::GetInterface(JSContext* aCx, nsIJSID* aIID,
                                   JS::MutableHandle<JS::Value> aRetval,
                                   ErrorResult& aError)
 {
   MOZ_ASSERT(IsInnerWindow());
@@ -7766,33 +7602,16 @@ nsGlobalWindowInner::CreateImageBitmap(J
   if (aImage.IsArrayBuffer() || aImage.IsArrayBufferView()) {
     return ImageBitmap::Create(this, aImage, aOffset, aLength, aFormat, aLayout,
                                aRv);
   }
   aRv.Throw(NS_ERROR_TYPE_ERR);
   return nullptr;
 }
 
-// Helper called by methods that move/resize the window,
-// to ensure the presContext (if any) is aware of resolution
-// change that may happen in multi-monitor configuration.
-void
-nsGlobalWindowInner::CheckForDPIChange()
-{
-  if (mDocShell) {
-    RefPtr<nsPresContext> presContext;
-    mDocShell->GetPresContext(getter_AddRefs(presContext));
-    if (presContext) {
-      if (presContext->DeviceContext()->CheckDPIChange()) {
-        presContext->UIResolutionChanged();
-      }
-    }
-  }
-}
-
 mozilla::dom::TabGroup*
 nsGlobalWindowInner::TabGroupInner()
 {
   MOZ_RELEASE_ASSERT(IsInnerWindow());
 
   // If we don't have a TabGroup yet, try to get it from the outer window and
   // cache it.
   if (!mTabGroup) {
@@ -7844,46 +7663,16 @@ nsGlobalWindowInner::AbstractMainThreadF
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
   if (GetDocGroup()) {
     return GetDocGroup()->AbstractMainThreadFor(aCategory);
   }
   return DispatcherTrait::AbstractMainThreadFor(aCategory);
 }
 
-nsGlobalWindowInner::TemporarilyDisableDialogs::TemporarilyDisableDialogs(
-  nsGlobalWindowOuter* aWindow MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
-{
-  MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-
-  MOZ_ASSERT(aWindow);
-  nsGlobalWindowOuter* topWindowOuter = aWindow->GetScriptableTopInternal();
-  if (!topWindowOuter) {
-    NS_ERROR("nsGlobalWindowInner::TemporarilyDisableDialogs used without a top "
-             "window?");
-    return;
-  }
-
-  // TODO: Warn if no top window?
-  nsGlobalWindowInner* topWindow =
-    topWindowOuter->GetCurrentInnerWindowInternal();
-  if (topWindow) {
-    mTopWindow = topWindow;
-    mSavedDialogsEnabled = mTopWindow->mAreDialogsEnabled;
-    mTopWindow->mAreDialogsEnabled = false;
-  }
-}
-
-nsGlobalWindowInner::TemporarilyDisableDialogs::~TemporarilyDisableDialogs()
-{
-  if (mTopWindow) {
-    mTopWindow->mAreDialogsEnabled = mSavedDialogsEnabled;
-  }
-}
-
 Worklet*
 nsGlobalWindowInner::GetAudioWorklet(ErrorResult& aRv)
 {
   MOZ_RELEASE_ASSERT(IsInnerWindow());
 
   if (!mAudioWorklet) {
     nsIPrincipal* principal = GetPrincipal();
     if (!principal) {
--- a/dom/base/nsGlobalWindowInner.h
+++ b/dom/base/nsGlobalWindowInner.h
@@ -463,40 +463,19 @@ public:
   // 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();
 
-  class MOZ_RAII TemporarilyDisableDialogs
-  {
-  public:
-    explicit TemporarilyDisableDialogs(nsGlobalWindowOuter* 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<nsGlobalWindowInner> 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();
 
-  nsGlobalWindowOuter *GetOuterWindowInternal();
+  nsGlobalWindowOuter *GetOuterWindowInternal() const;
 
   bool IsCreatingInnerWindow() const
   {
     return mCreatingInnerWindow;
   }
 
   bool IsChromeWindow() const
   {
@@ -1248,18 +1227,16 @@ public:
                                       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);
 
-  static bool CanSetProperty(const char *aPrefName);
-
   void ScrollTo(const mozilla::CSSIntPoint& aScroll,
                 const mozilla::dom::ScrollOptions& aOptions);
 
   bool IsFrame();
 
   already_AddRefed<nsIWidget> GetMainWidget();
   nsIWidget* GetNearestWidget() const;
 
@@ -1316,20 +1293,16 @@ protected:
   nsGlobalWindowInner* InnerForSetTimeoutOrInterval(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);
 
-  // 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();
 
   // nsPIDOMWindow<T> should be able to see these helper methods.
   friend class nsPIDOMWindow<mozIDOMWindowProxy>;
@@ -1670,17 +1643,17 @@ nsGlobalWindowInner::GetContextInternal(
   if (mOuterWindow) {
     return GetOuterWindowInternal()->mContext;
   }
 
   return mContext;
 }
 
 inline nsGlobalWindowOuter*
-nsGlobalWindowInner::GetOuterWindowInternal()
+nsGlobalWindowInner::GetOuterWindowInternal() const
 {
   return nsGlobalWindowOuter::Cast(GetOuterWindow());
 }
 
 inline bool
 nsGlobalWindowInner::IsPopupSpamWindow()
 {
   if (IsInnerWindow() && !mOuterWindow) {
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -1303,54 +1303,44 @@ nsGlobalWindowOuter::IsBlackForCC(bool a
 
 //*****************************************************************************
 // nsGlobalWindowOuter::nsIScriptGlobalObject
 //*****************************************************************************
 
 nsresult
 nsGlobalWindowOuter::EnsureScriptEnvironment()
 {
-  nsGlobalWindowOuter* outer = GetOuterWindowInternal();
-  if (!outer) {
-    NS_WARNING("No outer window available!");
-    return NS_ERROR_FAILURE;
-  }
-
-  if (outer->GetWrapperPreserveColor()) {
+  if (GetWrapperPreserveColor()) {
     return NS_OK;
   }
 
-  NS_ASSERTION(!outer->GetCurrentInnerWindowInternal(),
+  NS_ASSERTION(!GetCurrentInnerWindowInternal(),
                "No cached wrapper, but we have an inner window?");
 
   // If this window is a [i]frame, don't bother GC'ing when the frame's context
   // is destroyed since a GC will happen when the frameset or host document is
   // destroyed anyway.
-  nsCOMPtr<nsIScriptContext> context = new nsJSContext(!IsFrame(), outer);
-
-  NS_ASSERTION(!outer->mContext, "Will overwrite mContext!");
+  nsCOMPtr<nsIScriptContext> context = new nsJSContext(!IsFrame(), this);
+
+  NS_ASSERTION(!mContext, "Will overwrite mContext!");
 
   // should probably assert the context is clean???
   context->WillInitializeContext();
 
   nsresult rv = context->InitContext();
   NS_ENSURE_SUCCESS(rv, rv);
 
-  outer->mContext = context;
+  mContext = context;
   return NS_OK;
 }
 
 nsIScriptContext *
 nsGlobalWindowOuter::GetScriptContext()
 {
-  nsGlobalWindowOuter* outer = GetOuterWindowInternal();
-  if (!outer) {
-    return nullptr;
-  }
-  return outer->mContext;
+  return mContext;
 }
 
 JSObject *
 nsGlobalWindowOuter::GetGlobalJSObject()
 {
   return FastGetGlobalJSObject();
 }
 
@@ -2254,16 +2244,20 @@ nsGlobalWindowOuter::SetOpenerWindow(nsP
 #ifdef DEBUG
   mSetOpenerWindowCalled = true;
 #endif
 }
 
 void
 nsGlobalWindowOuter::UpdateParentTarget()
 {
+  // NOTE: This method is identical to
+  // nsGlobalWindowInner::UpdateParentTarget(). IF YOU UPDATE THIS METHOD,
+  // UPDATE THE OTHER ONE TOO!
+
   // Try to get our frame element's tab child global (its in-process message
   // manager).  If that fails, fall back to the chrome event handler's tab
   // child global, and if it doesn't have one, just use the chrome event
   // handler itself.
 
   nsCOMPtr<Element> frameElement = GetOuterWindow()->GetFrameElementInternal();
   nsCOMPtr<EventTarget> eventTarget =
     TryGetTabChildGlobalAsEventTarget(frameElement);
@@ -6393,33 +6387,24 @@ nsGlobalWindowOuter::NotifyWindowIDDestr
   if (NS_SUCCEEDED(rv)) {
     mNotifiedIDDestroyed = true;
   }
 }
 
 JSObject*
 nsGlobalWindowOuter::GetCachedXBLPrototypeHandler(nsXBLPrototypeHandler* aKey)
 {
-  JS::Rooted<JSObject*> handler(RootingCx());
-  if (mCachedXBLPrototypeHandlers) {
-    mCachedXBLPrototypeHandlers->Get(aKey, handler.address());
-  }
-  return handler;
+  MOZ_CRASH("Virtual inner window only function");
 }
 
 void
 nsGlobalWindowOuter::CacheXBLPrototypeHandler(nsXBLPrototypeHandler* aKey,
                                               JS::Handle<JSObject*> aHandler)
 {
-  if (!mCachedXBLPrototypeHandlers) {
-    mCachedXBLPrototypeHandlers = MakeUnique<XBLPrototypeHandlerTable>();
-    PreserveWrapper(ToSupports(this));
-  }
-
-  mCachedXBLPrototypeHandlers->Put(aKey, aHandler);
+  MOZ_CRASH("Virtual inner window only function");
 }
 
 Element*
 nsGlobalWindowOuter::GetFrameElementOuter(nsIPrincipal& aSubjectPrincipal)
 {
   MOZ_RELEASE_ASSERT(IsOuterWindow());
 
   if (!mDocShell || mDocShell->GetIsMozBrowser()) {
@@ -6594,78 +6579,52 @@ nsGlobalWindowOuter::GetOwnerGlobalForBi
   return this;
 }
 
 NS_IMETHODIMP
 nsGlobalWindowOuter::RemoveEventListener(const nsAString& aType,
                                          nsIDOMEventListener* aListener,
                                          bool aUseCapture)
 {
-  if (RefPtr<EventListenerManager> elm = GetExistingListenerManager()) {
-    elm->RemoveEventListener(aType, aListener, aUseCapture);
-  }
-  return NS_OK;
+  FORWARD_TO_INNER(RemoveEventListener, (aType, aListener, aUseCapture), NS_OK);
 }
 
 NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsGlobalWindowOuter)
 
 NS_IMETHODIMP
 nsGlobalWindowOuter::DispatchEvent(nsIDOMEvent* aEvent, bool* aRetVal)
 {
   FORWARD_TO_INNER(DispatchEvent, (aEvent, aRetVal), NS_OK);
 }
 
 NS_IMETHODIMP
 nsGlobalWindowOuter::AddEventListener(const nsAString& aType,
                                       nsIDOMEventListener *aListener,
                                       bool aUseCapture, bool aWantsUntrusted,
                                       uint8_t aOptionalArgc)
 {
-  NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1,
-               "Won't check if this is chrome, you want to set "
-               "aWantsUntrusted to false or make the aWantsUntrusted "
-               "explicit by making optional_argc non-zero.");
-
-  if (!aWantsUntrusted &&
-      (aOptionalArgc < 2 && !nsContentUtils::IsChromeDoc(mDoc))) {
-    aWantsUntrusted = true;
-  }
-
-  EventListenerManager* manager = GetOrCreateListenerManager();
-  NS_ENSURE_STATE(manager);
-  manager->AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted);
-  return NS_OK;
+  FORWARD_TO_INNER_CREATE(AddEventListener,
+                          (aType, aListener, aUseCapture, aWantsUntrusted, aOptionalArgc),
+                          NS_ERROR_UNEXPECTED);
 }
 
 void
 nsGlobalWindowOuter::AddEventListener(const nsAString& aType,
                                       EventListener* aListener,
                                       const AddEventListenerOptionsOrBoolean& aOptions,
                                       const Nullable<bool>& aWantsUntrusted,
                                       ErrorResult& aRv)
 {
   if (mInnerWindow && !nsContentUtils::CanCallerAccess(mInnerWindow)) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return;
   }
 
-  bool wantsUntrusted;
-  if (aWantsUntrusted.IsNull()) {
-    wantsUntrusted = !nsContentUtils::IsChromeDoc(mDoc);
-  } else {
-    wantsUntrusted = aWantsUntrusted.Value();
-  }
-
-  EventListenerManager* manager = GetOrCreateListenerManager();
-  if (!manager) {
-    aRv.Throw(NS_ERROR_UNEXPECTED);
-    return;
-  }
-
-  manager->AddEventListener(aType, aListener, aOptions, wantsUntrusted);
+  FORWARD_TO_INNER_CREATE(AddEventListener,
+                          (aType, aListener, aOptions, aWantsUntrusted, aRv),);
 }
 
 NS_IMETHODIMP
 nsGlobalWindowOuter::AddSystemEventListener(const nsAString& aType,
                                             nsIDOMEventListener *aListener,
                                             bool aUseCapture,
                                             bool aWantsUntrusted,
                                             uint8_t aOptionalArgc)
@@ -7065,18 +7024,18 @@ nsGlobalWindowOuter::GetComputedStyleHel
 
   return compStyle.forget();
 }
 
 //*****************************************************************************
 // nsGlobalWindowOuter::nsIInterfaceRequestor
 //*****************************************************************************
 
-NS_IMETHODIMP
-nsGlobalWindowOuter::GetInterface(const nsIID & aIID, void **aSink)
+nsresult
+nsGlobalWindowOuter::GetInterfaceInternal(const nsIID& aIID, void** aSink)
 {
   NS_ENSURE_ARG_POINTER(aSink);
   *aSink = nullptr;
 
   if (aIID.Equals(NS_GET_IID(nsIDocCharset))) {
     nsGlobalWindowOuter* outer = GetOuterWindowInternal();
     NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
 
@@ -7126,23 +7085,30 @@ nsGlobalWindowOuter::GetInterface(const 
   }
   else if (aIID.Equals(NS_GET_IID(nsILoadContext))) {
     nsGlobalWindowOuter* outer = GetOuterWindowInternal();
     NS_ENSURE_TRUE(outer, NS_ERROR_NOT_INITIALIZED);
 
     nsCOMPtr<nsILoadContext> loadContext(do_QueryInterface(outer->mDocShell));
     loadContext.forget(aSink);
   }
-  else {
-    return QueryInterface(aIID, aSink);
-  }
 
   return *aSink ? NS_OK : NS_ERROR_NO_INTERFACE;
 }
 
+NS_IMETHODIMP
+nsGlobalWindowOuter::GetInterface(const nsIID & aIID, void **aSink)
+{
+  nsresult rv = GetInterfaceInternal(aIID, aSink);
+  if (rv == NS_ERROR_NO_INTERFACE) {
+    return QueryInterface(aIID, aSink);
+  }
+  return rv;
+}
+
 nsresult
 nsGlobalWindowOuter::RegisterIdleObserver(nsIIdleObserver* aIdleObserver)
 {
   MOZ_CRASH("Virtual inner window only function");
 }
 
 nsresult
 nsGlobalWindowOuter::UnregisterIdleObserver(nsIIdleObserver* aIdleObserver)
@@ -7921,33 +7887,16 @@ nsGlobalWindowOuter::ReportLargeAllocSta
 
   nsContentUtils::ReportToConsole(errorFlags,
                                   NS_LITERAL_CSTRING("DOM"),
                                   mDoc,
                                   nsContentUtils::eDOM_PROPERTIES,
                                   message);
 }
 
-void
-nsGlobalWindowOuter::RedefineProperty(JSContext* aCx, const char* aPropName,
-                                 JS::Handle<JS::Value> aValue,
-                                 ErrorResult& aError)
-{
-  JS::Rooted<JSObject*> thisObj(aCx, GetWrapperPreserveColor());
-  if (!thisObj) {
-    aError.Throw(NS_ERROR_UNEXPECTED);
-    return;
-  }
-
-  if (!JS_WrapObject(aCx, &thisObj) ||
-      !JS_DefineProperty(aCx, thisObj, aPropName, aValue, JSPROP_ENUMERATE)) {
-    aError.Throw(NS_ERROR_FAILURE);
-  }
-}
-
 #ifdef _WINDOWS_
 #error "Never include windows.h in this file!"
 #endif
 
 // Helper called by methods that move/resize the window,
 // to ensure the presContext (if any) is aware of resolution
 // change that may happen in multi-monitor configuration.
 void
--- a/dom/base/nsGlobalWindowOuter.h
+++ b/dom/base/nsGlobalWindowOuter.h
@@ -818,36 +818,16 @@ public:
 
   already_AddRefed<nsWindowRoot> GetWindowRootOuter();
 
   virtual bool IsInSyncOperation() override
   {
     return GetExtantDoc() && GetExtantDoc()->IsInSyncOperation();
   }
 
-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
-    (nsGlobalWindowOuter::*WindowCoordGetter)(mozilla::dom::CallerType aCallerType,
-                                              mozilla::ErrorResult&);
-  typedef void
-    (nsGlobalWindowOuter::*WindowCoordSetter)(int32_t,
-                                              mozilla::dom::CallerType aCallerType,
-                                              mozilla::ErrorResult&);
-  // And the implementations of WindowCoordGetter/WindowCoordSetter.
 public:
   int32_t GetInnerWidthOuter(mozilla::ErrorResult& aError);
 protected:
   nsresult GetInnerWidth(int32_t* aWidth) override;
   void SetInnerWidthOuter(int32_t aInnerWidth,
                           mozilla::dom::CallerType aCallerType,
                           mozilla::ErrorResult& aError);
 public:
@@ -1173,16 +1153,18 @@ private:
       nsIMessageBroadcaster* mm = iter.UserData();
       if (mm) {
         static_cast<nsFrameMessageManager*>(mm)->Disconnect();
       }
     }
     mChromeFields.mGroupMessageManagers.Clear();
   }
 
+  nsresult GetInterfaceInternal(const nsIID& aIID, void** aSink);
+
 public:
   // Dispatch a runnable related to the global.
   virtual nsresult Dispatch(mozilla::TaskCategory aCategory,
                             already_AddRefed<nsIRunnable>&& aRunnable) override;
 
   virtual nsISerialEventTarget*
   EventTargetFor(mozilla::TaskCategory aCategory) const override;
 
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -249,19 +249,21 @@ public:
   // suspended and frozen by default.
   virtual bool IsSuspended() const = 0;
   virtual bool IsFrozen() const = 0;
 
   // Fire any DOM notification events related to things that happened while
   // the window was frozen.
   virtual nsresult FireDelayedDOMEvents() = 0;
 
-  nsPIDOMWindowOuter* GetOuterWindow()
+  nsPIDOMWindowOuter* GetOuterWindow() const
   {
-    return mIsInnerWindow ? mOuterWindow.get() : AsOuter();
+    return mIsInnerWindow
+      ? mOuterWindow.get()
+      : const_cast<nsPIDOMWindowOuter*>(AsOuter());
   }
 
   bool IsInnerWindow() const
   {
     return mIsInnerWindow;
   }
 
   bool IsOuterWindow() const