Merge inbound to mozilla-central. a=merge
authorarthur.iakab <aiakab@mozilla.com>
Tue, 03 Apr 2018 12:31:23 +0300
changeset 411437 4a3275936ddf871103b53e00608e2b8d5aee7e69
parent 411430 2ee160335e150f20df3471b60b5e58ce873e2ff6 (current diff)
parent 411436 efce674123ace94d821157b996f0d5caa7380620 (diff)
child 411438 5ec55f7a95f94cf39d57cdf36abecab914ea48eb
child 411453 801d1d90b2ffcca423d9cee10509169318890b8c
child 411503 99a953f1823fcf96d6f312b356a11f245a9b0c78
push id33756
push useraiakab@mozilla.com
push dateTue, 03 Apr 2018 09:31:57 +0000
treeherdermozilla-central@4a3275936ddf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone61.0a1
first release with
nightly linux32
4a3275936ddf / 61.0a1 / 20180403100105 / files
nightly linux64
4a3275936ddf / 61.0a1 / 20180403100105 / files
nightly mac
4a3275936ddf / 61.0a1 / 20180403100105 / files
nightly win32
4a3275936ddf / 61.0a1 / 20180403100105 / files
nightly win64
4a3275936ddf / 61.0a1 / 20180403100105 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
dom/interfaces/base/nsIDOMScreen.idl
--- a/devtools/client/framework/components/toolbox-tab.js
+++ b/devtools/client/framework/components/toolbox-tab.js
@@ -57,16 +57,21 @@ class ToolboxTab extends Component {
         id: `toolbox-tab-${id}`,
         "data-id": id,
         title: tooltip,
         type: "button",
         "aria-pressed": currentToolId === id ? "true" : "false",
         tabIndex: focusedButton === id ? "0" : "-1",
         onFocus: () => focusButton(id),
         onMouseDown: () => selectTool(id),
+        onKeyDown: (evt) => {
+          if (evt.key === "Enter" || evt.key === " ") {
+            selectTool(id);
+          }
+        },
       },
       span(
         {
           className: "devtools-tab-line"
         }
       ),
       ...this.renderIcon(panelDefinition, isHighlighted),
       iconOnly ?
--- a/devtools/client/framework/test/browser_toolbox_keyboard_navigation.js
+++ b/devtools/client/framework/test/browser_toolbox_keyboard_navigation.js
@@ -76,8 +76,49 @@ add_task(async function () {
   EventUtils.synthesizeKey("KEY_Tab");
   ok(!containsFocus(doc, toolbar), "Focus is outside of the toolbar");
 
   // Move the focus back to the toolbar, ensure we land on the last active
   // descendant control.
   EventUtils.synthesizeKey("KEY_Tab", {shiftKey: true});
   is(doc.activeElement.id, expectedFocusedControl.id, "New control is focused");
 });
+
+// Test that moving the focus of tab button and selecting it.
+add_task(async function () {
+  info("Create a test tab and open the toolbox");
+  let toolbox = await openNewTabAndToolbox(TEST_URL, "inspector");
+  let doc = toolbox.doc;
+
+  let toolbar = doc.querySelector(".toolbox-tabs");
+  let tabButtons = toolbar.querySelectorAll(".devtools-tab, button");
+  let win = tabButtons[0].ownerDocument.defaultView;
+
+  // Put the keyboard focus onto the first tab button.
+  tabButtons[0].focus();
+  ok(containsFocus(doc, toolbar), "Focus is within the toolbox");
+  is(doc.activeElement.id, tabButtons[0].id, "First tab button is focused.");
+
+  // Move the focused tab and select it by using enter key.
+  let onKeyEvent = once(win, "keydown");
+  EventUtils.synthesizeKey("KEY_ArrowRight");
+  await onKeyEvent;
+
+  let onceSelected = toolbox.once("webconsole-selected");
+  EventUtils.synthesizeKey("Enter");
+  await onceSelected;
+  ok(doc.activeElement.id, tabButtons[1].id, "Changed tab button is focused.");
+
+  // Webconsole steal the focus from button after sending "webconsole-selected"
+  // event.
+  tabButtons[1].focus();
+
+  // Return the focused tab with space key.
+  onKeyEvent = once(win, "keydown");
+  EventUtils.synthesizeKey("KEY_ArrowLeft");
+  await onKeyEvent;
+
+  onceSelected = toolbox.once("inspector-selected");
+  EventUtils.synthesizeKey(" ");
+  await onceSelected;
+
+  ok(doc.activeElement.id, tabButtons[0].id, "Changed tab button is focused.");
+});
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -2327,25 +2327,16 @@ nsGlobalWindowInner::GetScreen(ErrorResu
       aError.Throw(NS_ERROR_UNEXPECTED);
       return nullptr;
     }
   }
 
   return mScreen;
 }
 
-nsIDOMScreen*
-nsGlobalWindowInner::GetScreen()
-{
-  ErrorResult dummy;
-  nsIDOMScreen* screen = GetScreen(dummy);
-  dummy.SuppressException();
-  return screen;
-}
-
 nsHistory*
 nsGlobalWindowInner::GetHistory(ErrorResult& aError)
 {
   if (!mHistory) {
     mHistory = new nsHistory(this);
   }
 
   return mHistory;
--- a/dom/base/nsGlobalWindowInner.h
+++ b/dom/base/nsGlobalWindowInner.h
@@ -774,17 +774,16 @@ public:
   already_AddRefed<nsICSSDeclaration>
     GetComputedStyle(mozilla::dom::Element& aElt, const nsAString& aPseudoElt,
                      mozilla::ErrorResult& aError) override;
   already_AddRefed<mozilla::dom::MediaQueryList> MatchMedia(
     const nsAString& aQuery,
     mozilla::dom::CallerType aCallerType,
     mozilla::ErrorResult& aError);
   nsScreen* GetScreen(mozilla::ErrorResult& aError);
-  nsIDOMScreen* GetScreen() override;
   void MoveTo(int32_t aXPos, int32_t aYPos,
               mozilla::dom::CallerType aCallerType,
               mozilla::ErrorResult& aError);
   void MoveBy(int32_t aXDif, int32_t aYDif,
               mozilla::dom::CallerType aCallerType,
               mozilla::ErrorResult& aError);
   void ResizeTo(int32_t aWidth, int32_t aHeight,
                 mozilla::dom::CallerType aCallerType,
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -2591,20 +2591,20 @@ nsPIDOMWindowOuter::SetFrameElementInter
 }
 
 Navigator*
 nsGlobalWindowOuter::GetNavigator()
 {
   FORWARD_TO_INNER(Navigator, (), nullptr);
 }
 
-nsIDOMScreen*
+nsScreen*
 nsGlobalWindowOuter::GetScreen()
 {
-  FORWARD_TO_INNER(GetScreen, (), nullptr);
+  FORWARD_TO_INNER(GetScreen, (IgnoreErrors()), nullptr);
 }
 
 void
 nsPIDOMWindowOuter::MaybeActiveMediaComponents()
 {
   if (mMediaSuspend != nsISuspendedTypes::SUSPENDED_BLOCK) {
     return;
   }
@@ -3703,48 +3703,47 @@ nsGlobalWindowOuter::CheckSecurityLeftAn
 #endif
 
     if (nsGlobalWindowOuter* rootWindow = nsGlobalWindowOuter::Cast(GetPrivateRoot())) {
       rootWindow->FlushPendingNotifications(FlushType::Layout);
     }
 
     nsCOMPtr<nsIBaseWindow> treeOwner = GetTreeOwnerWindow();
 
-    nsCOMPtr<nsIDOMScreen> screen = GetScreen();
+    RefPtr<nsScreen> screen = GetScreen();
 
     if (treeOwner && screen) {
-      int32_t screenLeft, screenTop, screenWidth, screenHeight;
       int32_t winLeft, winTop, winWidth, winHeight;
 
       // Get the window size
       treeOwner->GetPositionAndSize(&winLeft, &winTop, &winWidth, &winHeight);
 
       // convert those values to CSS pixels
       // XXX four separate retrievals of the prescontext
       winLeft   = DevToCSSIntPixels(winLeft);
       winTop    = DevToCSSIntPixels(winTop);
       winWidth  = DevToCSSIntPixels(winWidth);
       winHeight = DevToCSSIntPixels(winHeight);
 
       // Get the screen dimensions
       // XXX This should use nsIScreenManager once it's fully fleshed out.
-      screen->GetAvailLeft(&screenLeft);
-      screen->GetAvailWidth(&screenWidth);
-      screen->GetAvailHeight(&screenHeight);
+      int32_t screenLeft = screen->GetAvailLeft(IgnoreErrors());
+      int32_t screenWidth = screen->GetAvailWidth(IgnoreErrors());
+      int32_t screenHeight = screen->GetAvailHeight(IgnoreErrors());
 #if defined(XP_MACOSX)
       /* The mac's coordinate system is different from the assumed Windows'
          system. It offsets by the height of the menubar so that a window
          placed at (0,0) will be entirely visible. Unfortunately that
          correction is made elsewhere (in Widget) and the meaning of
          the Avail... coordinates is overloaded. Here we allow a window
          to be placed at (0,0) because it does make sense to do so.
       */
-      screen->GetTop(&screenTop);
+      int32_t screenTop = screen->GetTop(IgnoreErrors());
 #else
-      screen->GetAvailTop(&screenTop);
+      int32_t screenTop = screen->GetAvailTop(IgnoreErrors());
 #endif
 
       if (aLeft) {
         if (screenLeft+screenWidth < *aLeft+winWidth)
           *aLeft = screenLeft+screenWidth - winWidth;
         if (screenLeft > *aLeft)
           *aLeft = screenLeft;
       }
--- a/dom/base/nsGlobalWindowOuter.h
+++ b/dom/base/nsGlobalWindowOuter.h
@@ -631,17 +631,17 @@ public:
                    nsIPrincipal& aSubjectPrincipal,
                    mozilla::ErrorResult& aError);
   void PrintOuter(mozilla::ErrorResult& aError);
   mozilla::dom::Selection* GetSelectionOuter();
   already_AddRefed<nsISelection> GetSelection() override;
   already_AddRefed<mozilla::dom::MediaQueryList> MatchMediaOuter(
     const nsAString& aQuery,
     mozilla::dom::CallerType aCallerType);
-  nsIDOMScreen* GetScreen() override;
+  nsScreen* GetScreen();
   void MoveToOuter(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);
   nsresult MoveBy(int32_t aXDif, int32_t aYDif) override;
   void ResizeToOuter(int32_t aWidth, int32_t aHeight,
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -585,17 +585,16 @@ public:
     mMarkedCCGeneration = aGeneration;
   }
 
   uint32_t GetMarkedCCGeneration()
   {
     return mMarkedCCGeneration;
   }
 
-  virtual nsIDOMScreen* GetScreen() = 0;
   mozilla::dom::Navigator* Navigator();
   virtual mozilla::dom::Location* GetLocation() = 0;
 
   virtual nsresult GetControllers(nsIControllers** aControllers) = 0;
 
   virtual already_AddRefed<nsIDOMWindowCollection> GetFrames() = 0;
 
   virtual nsresult GetInnerWidth(int32_t* aWidth) = 0;
@@ -1089,17 +1088,16 @@ public:
 
   uint32_t GetMarkedCCGeneration()
   {
     return mMarkedCCGeneration;
   }
 
   // XXX(nika): These feel like they should be inner window only, but they're
   // called on the outer window.
-  virtual nsIDOMScreen* GetScreen() = 0;
   virtual mozilla::dom::Navigator* GetNavigator() = 0;
   virtual mozilla::dom::Location* GetLocation() = 0;
 
   virtual nsresult GetPrompter(nsIPrompt** aPrompt) = 0;
   virtual nsresult GetControllers(nsIControllers** aControllers) = 0;
   virtual already_AddRefed<nsISelection> GetSelection() = 0;
   virtual already_AddRefed<nsPIDOMWindowOuter> GetOpener() = 0;
 
--- a/dom/base/nsScreen.cpp
+++ b/dom/base/nsScreen.cpp
@@ -45,17 +45,16 @@ nsScreen::nsScreen(nsPIDOMWindowInner* a
 
 nsScreen::~nsScreen()
 {
 }
 
 
 // QueryInterface implementation for nsScreen
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsScreen)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMScreen)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(nsScreen, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(nsScreen, DOMEventTargetHelper)
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(nsScreen,
                                    DOMEventTargetHelper,
                                    mScreenOrientation)
@@ -75,32 +74,16 @@ nsScreen::GetPixelDepth(ErrorResult& aRv
     return -1;
   }
 
   uint32_t depth;
   context->GetDepth(depth);
   return depth;
 }
 
-#define FORWARD_LONG_GETTER(_name)                                              \
-  NS_IMETHODIMP                                                                 \
-  nsScreen::Get ## _name(int32_t* aOut)                                         \
-  {                                                                             \
-    ErrorResult rv;                                                             \
-    *aOut = Get ## _name(rv);                                                   \
-    return rv.StealNSResult();                                                  \
-  }
-
-FORWARD_LONG_GETTER(AvailWidth)
-FORWARD_LONG_GETTER(AvailHeight)
-
-FORWARD_LONG_GETTER(Top)
-FORWARD_LONG_GETTER(AvailTop)
-FORWARD_LONG_GETTER(AvailLeft)
-
 nsPIDOMWindowOuter*
 nsScreen::GetOuter() const
 {
   if (nsPIDOMWindowInner* inner = GetOwner()) {
     return inner->GetOuterWindow();
   }
 
   return nullptr;
--- a/dom/base/nsScreen.h
+++ b/dom/base/nsScreen.h
@@ -5,32 +5,29 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef nsScreen_h___
 #define nsScreen_h___
 
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/ScreenOrientation.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/ErrorResult.h"
-#include "nsIDOMScreen.h"
 #include "nsCOMPtr.h"
 #include "nsRect.h"
 
 class nsDeviceContext;
 
 // Script "screen" object
 class nsScreen : public mozilla::DOMEventTargetHelper
-               , public nsIDOMScreen
 {
   typedef mozilla::ErrorResult ErrorResult;
 public:
   static already_AddRefed<nsScreen> Create(nsPIDOMWindowInner* aWindow);
 
   NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_NSIDOMSCREEN
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsScreen, mozilla::DOMEventTargetHelper)
   NS_REALLY_FORWARD_NSIDOMEVENTTARGET(mozilla::DOMEventTargetHelper)
 
   nsPIDOMWindowInner* GetParentObject() const
   {
     return GetOwner();
   }
 
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -2184,16 +2184,17 @@ class PropertyDefiner:
         lastCondition = getCondition(array[0], self.descriptor)
 
         specs = []
         disablers = []
         prefableSpecs = []
 
         disablersTemplate = dedent(
             """
+            // Can't be const because the pref-enabled boolean needs to be writable
             static PrefableDisablers %s_disablers%d = {
               true, %s, %s, %s
             };
             """)
         prefableWithDisablersTemplate = '  { &%s_disablers%d, &%s_specs[%d] }'
         prefableWithoutDisablersTemplate = '  { nullptr, &%s_specs[%d] }'
         prefCacheTemplate = '&%s[%d].disablers->enabled'
 
@@ -2252,18 +2253,17 @@ class PropertyDefiner:
             static ${specType} ${name}_specs[] = {
             ${specs}
             };
             #if defined(__clang__)
             #pragma clang diagnostic pop
             #endif
 
             ${disablers}
-            // Can't be const because the pref-enabled boolean needs to be writable
-            static Prefable<${specType}> ${name}[] = {
+            static const Prefable<${specType}> ${name}[] = {
             ${prefableSpecs}
             };
 
             """,
             specType=specType,
             name=name,
             disablers='\n'.join(disablers),
             specs=',\n'.join(specs),
--- a/dom/interfaces/base/domstubs.idl
+++ b/dom/interfaces/base/domstubs.idl
@@ -29,17 +29,16 @@ namespace dom {
 class DOMException;
 }
 }
 %}
 
 // Base
 interface nsIDOMWindow;
 interface nsIDOMWindowCollection;
-interface nsIDOMScreen;
 
 // Events
 interface nsIDOMEvent;
 interface nsIDOMEventTarget;
 interface nsIDOMEventListener;
 
 // HTML
 interface nsIDOMHTMLHeadElement;
--- a/dom/interfaces/base/moz.build
+++ b/dom/interfaces/base/moz.build
@@ -12,17 +12,16 @@ XPIDL_SOURCES += [
     'nsIBrowser.idl',
     'nsIBrowserDOMWindow.idl',
     'nsIContentPermissionPrompt.idl',
     'nsIContentPrefService2.idl',
     'nsIContentProcess.idl',
     'nsIContentURIGrouper.idl',
     'nsIDOMChromeWindow.idl',
     'nsIDOMGlobalPropertyInitializer.idl',
-    'nsIDOMScreen.idl',
     'nsIDOMWindow.idl',
     'nsIDOMWindowCollection.idl',
     'nsIDOMWindowUtils.idl',
     'nsIFocusManager.idl',
     'nsIIdleObserver.idl',
     'nsIQueryContentEventResult.idl',
     'nsIRemoteBrowser.idl',
     'nsIServiceWorkerManager.idl',
deleted file mode 100644
--- a/dom/interfaces/base/nsIDOMScreen.idl
+++ /dev/null
@@ -1,16 +0,0 @@
-/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsIDOMEventTarget.idl"
-
-[builtinclass, uuid(82c7924b-4b46-4e5a-a8d2-6edb5fc0a60d)]
-interface nsIDOMScreen : nsIDOMEventTarget
-{
-  readonly attribute long             top;
-  readonly attribute long             availWidth;
-  readonly attribute long             availHeight;
-  readonly attribute long             availLeft;
-  readonly attribute long             availTop;
-};
--- a/editor/spellchecker/TextServicesDocument.cpp
+++ b/editor/spellchecker/TextServicesDocument.cpp
@@ -26,17 +26,16 @@
 #include "nsIPlaintextEditor.h"         // for nsIPlaintextEditor
 #include "nsISelection.h"               // for nsISelection
 #include "nsISelectionController.h"     // for nsISelectionController, etc
 #include "nsISupportsBase.h"            // for nsISupports
 #include "nsISupportsUtils.h"           // for NS_IF_ADDREF, NS_ADDREF, etc
 #include "nsITextServicesFilter.h"      // for nsITextServicesFilter
 #include "mozilla/intl/WordBreaker.h"   // for WordRange, WordBreaker
 #include "nsRange.h"                    // for nsRange
-#include "nsStaticAtom.h"               // for NS_STATIC_ATOM_SETUP, etc
 #include "nsString.h"                   // for nsString, nsAutoString
 #include "nscore.h"                     // for nsresult, NS_IMETHODIMP, etc
 
 #define LOCK_DOC(doc)
 #define UNLOCK_DOC(doc)
 
 namespace mozilla {
 
--- a/layout/style/nsCSSAnonBoxes.cpp
+++ b/layout/style/nsCSSAnonBoxes.cpp
@@ -4,76 +4,73 @@
  * 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/. */
 
 /* atom list for CSS anonymous boxes */
 
 #include "mozilla/ArrayUtils.h"
 
 #include "nsCSSAnonBoxes.h"
-#include "nsStaticAtom.h"
 
 using namespace mozilla;
 
 namespace mozilla {
 namespace detail {
 
 MOZ_PUSH_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
 extern constexpr CSSAnonBoxAtoms gCSSAnonBoxAtoms = {
   #define CSS_ANON_BOX(name_, value_) \
     NS_STATIC_ATOM_INIT_STRING(value_)
   #include "nsCSSAnonBoxList.h"
   #undef CSS_ANON_BOX
-
-  #define CSS_ANON_BOX(name_, value_) \
-    NS_STATIC_ATOM_INIT_ATOM(CSSAnonBoxAtoms, name_, value_)
-  #include "nsCSSAnonBoxList.h"
-  #undef CSS_ANON_BOX
+  {
+    #define CSS_ANON_BOX(name_, value_) \
+      NS_STATIC_ATOM_INIT_ATOM( \
+        nsICSSAnonBoxPseudo, CSSAnonBoxAtoms, name_, value_)
+    #include "nsCSSAnonBoxList.h"
+    #undef CSS_ANON_BOX
+  }
 };
 MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
 
 } // namespace detail
 } // namespace mozilla
 
+// Non-inheriting boxes must come first in nsCSSAnonBoxList.h so that
+// `NonInheriting` values can index into this array and other similar arrays.
+const nsStaticAtom* const nsCSSAnonBoxes::sAtoms =
+  mozilla::detail::gCSSAnonBoxAtoms.mAtoms;
+
 #define CSS_ANON_BOX(name_, value_) \
-  NS_STATIC_ATOM_SUBCLASS_DEFN_PTR(nsICSSAnonBoxPseudo, nsCSSAnonBoxes, name_)
+  NS_STATIC_ATOM_DEFN_PTR( \
+    nsICSSAnonBoxPseudo, mozilla::detail::CSSAnonBoxAtoms, \
+    mozilla::detail::gCSSAnonBoxAtoms, nsCSSAnonBoxes, name_)
 #include "nsCSSAnonBoxList.h"
 #undef CSS_ANON_BOX
 
-static const nsStaticAtomSetup sCSSAnonBoxAtomSetup[] = {
-  // Non-inheriting boxes must come first in nsCSSAnonBoxList.h so that
-  // `NonInheriting` values can index into this array and other similar arrays.
-  #define CSS_ANON_BOX(name_, value_) \
-    NS_STATIC_ATOM_SUBCLASS_SETUP( \
-      mozilla::detail::gCSSAnonBoxAtoms, nsCSSAnonBoxes, name_)
-  #include "nsCSSAnonBoxList.h"
-  #undef CSS_ANON_BOX
-};
-
 void nsCSSAnonBoxes::RegisterStaticAtoms()
 {
-  NS_RegisterStaticAtoms(sCSSAnonBoxAtomSetup);
+  NS_RegisterStaticAtoms(sAtoms, sAtomsLen);
 }
 
 bool nsCSSAnonBoxes::IsAnonBox(nsAtom *aAtom)
 {
-  return nsStaticAtomUtils::IsMember(aAtom, sCSSAnonBoxAtomSetup);
+  return nsStaticAtomUtils::IsMember(aAtom, sAtoms, sAtomsLen);
 }
 
 #ifdef MOZ_XUL
 /* static */ bool
 nsCSSAnonBoxes::IsTreePseudoElement(nsAtom* aPseudo)
 {
   MOZ_ASSERT(nsCSSAnonBoxes::IsAnonBox(aPseudo));
   return StringBeginsWith(nsDependentAtomString(aPseudo),
                           NS_LITERAL_STRING(":-moz-tree-"));
 }
 #endif
 
 /* static*/ nsCSSAnonBoxes::NonInheriting
 nsCSSAnonBoxes::NonInheritingTypeForPseudoTag(nsAtom* aPseudo)
 {
   MOZ_ASSERT(IsNonInheritingAnonBox(aPseudo));
-  Maybe<uint32_t> index =
-    nsStaticAtomUtils::Lookup(aPseudo, sCSSAnonBoxAtomSetup);
+  Maybe<uint32_t> index = nsStaticAtomUtils::Lookup(aPseudo, sAtoms, sAtomsLen);
   MOZ_RELEASE_ASSERT(index.isSome());
   return static_cast<NonInheriting>(*index);
 }
--- a/layout/style/nsCSSAnonBoxes.h
+++ b/layout/style/nsCSSAnonBoxes.h
@@ -7,32 +7,45 @@
 /* atom list for CSS anonymous boxes */
 
 #ifndef nsCSSAnonBoxes_h___
 #define nsCSSAnonBoxes_h___
 
 #include "nsAtom.h"
 #include "nsStaticAtom.h"
 
-// Empty class derived from nsAtom so that function signatures can
-// require an atom from this atom list.
-class nsICSSAnonBoxPseudo : public nsAtom {};
+// Trivial subclass of nsStaticAtom so that function signatures can require an
+// atom from this atom list.
+class nsICSSAnonBoxPseudo : public nsStaticAtom
+{
+public:
+  constexpr nsICSSAnonBoxPseudo(const char16_t* aStr, uint32_t aLength,
+                                uint32_t aStringOffset)
+    : nsStaticAtom(aStr, aLength, aStringOffset)
+  {}
+};
 
 namespace mozilla {
 namespace detail {
 
 struct CSSAnonBoxAtoms
 {
   #define CSS_ANON_BOX(name_, value_) NS_STATIC_ATOM_DECL_STRING(name_, value_)
   #include "nsCSSAnonBoxList.h"
   #undef CSS_ANON_BOX
 
-  #define CSS_ANON_BOX(name_, value_) NS_STATIC_ATOM_DECL_ATOM(name_)
-  #include "nsCSSAnonBoxList.h"
-  #undef CSS_ANON_BOX
+  enum class Atoms {
+    #define CSS_ANON_BOX(name_, value_) \
+      NS_STATIC_ATOM_ENUM(name_)
+    #include "nsCSSAnonBoxList.h"
+    #undef CSS_ANON_BOX
+    AtomsCount
+  };
+
+  const nsICSSAnonBoxPseudo mAtoms[static_cast<size_t>(Atoms::AtomsCount)];
 };
 
 extern const CSSAnonBoxAtoms gCSSAnonBoxAtoms;
 
 } // namespace detail
 } // namespace mozilla
 
 class nsCSSAnonBoxes {
@@ -45,20 +58,26 @@ public:
   static bool IsTreePseudoElement(nsAtom* aPseudo);
 #endif
   static bool IsNonElement(nsAtom* aPseudo)
   {
     return aPseudo == mozText || aPseudo == oofPlaceholder ||
            aPseudo == firstLetterContinuation;
   }
 
-#define CSS_ANON_BOX(name_, value_) \
-  NS_STATIC_ATOM_SUBCLASS_DECL_PTR(nsICSSAnonBoxPseudo, name_)
-#include "nsCSSAnonBoxList.h"
-#undef CSS_ANON_BOX
+private:
+  static const nsStaticAtom* const sAtoms;
+  static constexpr size_t sAtomsLen =
+    mozilla::ArrayLength(mozilla::detail::gCSSAnonBoxAtoms.mAtoms);
+
+public:
+  #define CSS_ANON_BOX(name_, value_) \
+    NS_STATIC_ATOM_DECL_PTR(nsICSSAnonBoxPseudo, name_)
+  #include "nsCSSAnonBoxList.h"
+  #undef CSS_ANON_BOX
 
   typedef uint8_t NonInheritingBase;
   enum class NonInheriting : NonInheritingBase {
 #define CSS_ANON_BOX(_name, _value) /* nothing */
 #define CSS_NON_INHERITING_ANON_BOX(_name, _value) _name,
 #include "nsCSSAnonBoxList.h"
 #undef CSS_NON_INHERITING_ANON_BOX
 #undef CSS_ANON_BOX
--- a/layout/style/nsCSSPseudoElements.cpp
+++ b/layout/style/nsCSSPseudoElements.cpp
@@ -5,76 +5,70 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* atom list for CSS pseudo-elements */
 
 #include "nsCSSPseudoElements.h"
 
 #include "mozilla/ArrayUtils.h"
 
-#include "nsStaticAtom.h"
 #include "nsCSSAnonBoxes.h"
 #include "nsDOMString.h"
 
 using namespace mozilla;
 
 namespace mozilla {
 namespace detail {
 
 MOZ_PUSH_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
 extern constexpr CSSPseudoElementAtoms gCSSPseudoElementAtoms = {
   #define CSS_PSEUDO_ELEMENT(name_, value_, flags_) \
     NS_STATIC_ATOM_INIT_STRING(value_)
   #include "nsCSSPseudoElementList.h"
   #undef CSS_PSEUDO_ELEMENT
-
-  #define CSS_PSEUDO_ELEMENT(name_, value_, flags_) \
-    NS_STATIC_ATOM_INIT_ATOM(CSSPseudoElementAtoms, name_, value_)
-  #include "nsCSSPseudoElementList.h"
-  #undef CSS_PSEUDO_ELEMENT
+  {
+    #define CSS_PSEUDO_ELEMENT(name_, value_, flags_) \
+      NS_STATIC_ATOM_INIT_ATOM( \
+        nsICSSPseudoElement, CSSPseudoElementAtoms, name_, value_)
+    #include "nsCSSPseudoElementList.h"
+    #undef CSS_PSEUDO_ELEMENT
+  }
 };
 MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
 
 } // namespace detail
 } // namespace mozilla
 
+const nsStaticAtom* const nsCSSPseudoElements::sAtoms =
+  mozilla::detail::gCSSPseudoElementAtoms.mAtoms;
+
 #define CSS_PSEUDO_ELEMENT(name_, value_, flags_) \
-  NS_STATIC_ATOM_SUBCLASS_DEFN_PTR( \
-    nsICSSPseudoElement, nsCSSPseudoElements, name_)
+  NS_STATIC_ATOM_DEFN_PTR( \
+    nsICSSPseudoElement, mozilla::detail::CSSPseudoElementAtoms, \
+    mozilla::detail::gCSSPseudoElementAtoms, nsCSSPseudoElements, name_);
 #include "nsCSSPseudoElementList.h"
 #undef CSS_PSEUDO_ELEMENT
 
-// Array of nsStaticAtomSetup for each of the pseudo-elements.
-static const nsStaticAtomSetup sCSSPseudoElementAtomSetup[] = {
-  #define CSS_PSEUDO_ELEMENT(name_, value_, flags_) \
-    NS_STATIC_ATOM_SUBCLASS_SETUP( \
-      detail::gCSSPseudoElementAtoms, nsCSSPseudoElements, name_)
-  #include "nsCSSPseudoElementList.h"
-  #undef CSS_PSEUDO_ELEMENT
-};
-
-// Flags data for each of the pseudo-elements, which must be separate
-// from the previous array since there's no place for it in
-// nsStaticAtomSetup.
+// Flags data for each of the pseudo-elements.
 /* static */ const uint32_t
 nsCSSPseudoElements::kPseudoElementFlags[] = {
 #define CSS_PSEUDO_ELEMENT(name_, value_, flags_) \
   flags_,
 #include "nsCSSPseudoElementList.h"
 #undef CSS_PSEUDO_ELEMENT
 };
 
 void nsCSSPseudoElements::RegisterStaticAtoms()
 {
-  NS_RegisterStaticAtoms(sCSSPseudoElementAtomSetup);
+  NS_RegisterStaticAtoms(sAtoms, sAtomsLen);
 }
 
 bool nsCSSPseudoElements::IsPseudoElement(nsAtom *aAtom)
 {
-  return nsStaticAtomUtils::IsMember(aAtom, sCSSPseudoElementAtomSetup);
+  return nsStaticAtomUtils::IsMember(aAtom, sAtoms, sAtomsLen);
 }
 
 /* static */ bool
 nsCSSPseudoElements::IsCSS2PseudoElement(nsAtom *aAtom)
 {
   // We don't implement this using PseudoElementHasFlags because callers
   // want to pass things that could be anon boxes.
   NS_ASSERTION(nsCSSPseudoElements::IsPseudoElement(aAtom) ||
@@ -90,18 +84,17 @@ nsCSSPseudoElements::IsCSS2PseudoElement
                    CSS_PSEUDO_ELEMENT_IS_CSS2),
                "result doesn't match flags");
   return result;
 }
 
 /* static */ CSSPseudoElementType
 nsCSSPseudoElements::GetPseudoType(nsAtom *aAtom, EnabledState aEnabledState)
 {
-  Maybe<uint32_t> index =
-    nsStaticAtomUtils::Lookup(aAtom, sCSSPseudoElementAtomSetup);
+  Maybe<uint32_t> index = nsStaticAtomUtils::Lookup(aAtom, sAtoms, sAtomsLen);
   if (index.isSome()) {
     auto type = static_cast<Type>(*index);
     // ::moz-placeholder is an alias for ::placeholder
     if (type == CSSPseudoElementType::mozPlaceholder) {
       type = CSSPseudoElementType::placeholder;
     }
     return IsEnabled(type, aEnabledState) ? type : Type::NotPseudo;
   }
@@ -121,19 +114,19 @@ nsCSSPseudoElements::GetPseudoType(nsAto
   }
 
   return Type::NotPseudo;
 }
 
 /* static */ nsAtom*
 nsCSSPseudoElements::GetPseudoAtom(Type aType)
 {
-  NS_ASSERTION(aType < Type::Count, "Unexpected type");
-  return *sCSSPseudoElementAtomSetup[
-    static_cast<CSSPseudoElementTypeBase>(aType)].mAtomp;
+  MOZ_ASSERT(aType < Type::Count, "Unexpected type");
+  return const_cast<nsStaticAtom*>(
+    &sAtoms[static_cast<CSSPseudoElementTypeBase>(aType)]);
 }
 
 /* static */ already_AddRefed<nsAtom>
 nsCSSPseudoElements::GetPseudoAtom(const nsAString& aPseudoElement)
 {
   if (DOMStringIsNull(aPseudoElement) || aPseudoElement.IsEmpty() ||
       aPseudoElement.First() != char16_t(':')) {
     return nullptr;
--- a/layout/style/nsCSSPseudoElements.h
+++ b/layout/style/nsCSSPseudoElements.h
@@ -51,16 +51,27 @@
 // Can we use the ChromeOnly document.createElement(..., { pseudo: "::foo" })
 // API for creating pseudo-implementing native anonymous content in JS with this
 // pseudo-element?
 #define CSS_PSEUDO_ELEMENT_IS_JS_CREATED_NAC           (1<<6)
 // Does this pseudo-element act like an item for containers (such as flex and
 // grid containers) and thus needs parent display-based style fixup?
 #define CSS_PSEUDO_ELEMENT_IS_FLEX_OR_GRID_ITEM        (1<<7)
 
+// Trivial subclass of nsStaticAtom so that function signatures can require an
+// atom from this atom list.
+class nsICSSPseudoElement : public nsStaticAtom
+{
+public:
+  constexpr nsICSSPseudoElement(const char16_t* aStr, uint32_t aLength,
+                                uint32_t aStringOffset)
+    : nsStaticAtom(aStr, aLength, aStringOffset)
+  {}
+};
+
 namespace mozilla {
 
 // The total count of CSSPseudoElement is less than 256,
 // so use uint8_t as its underlying type.
 typedef uint8_t CSSPseudoElementTypeBase;
 enum class CSSPseudoElementType : CSSPseudoElementTypeBase {
   // If the actual pseudo-elements stop being first here, change
   // GetPseudoType.
@@ -83,32 +94,33 @@ namespace detail {
 
 struct CSSPseudoElementAtoms
 {
   #define CSS_PSEUDO_ELEMENT(name_, value_, flags_) \
     NS_STATIC_ATOM_DECL_STRING(name_, value_)
   #include "nsCSSPseudoElementList.h"
   #undef CSS_PSEUDO_ELEMENT
 
-  #define CSS_PSEUDO_ELEMENT(name_, value_, flags_) \
-    NS_STATIC_ATOM_DECL_ATOM(name_)
-  #include "nsCSSPseudoElementList.h"
-  #undef CSS_PSEUDO_ELEMENT
+  enum class Atoms {
+    #define CSS_PSEUDO_ELEMENT(name_, value_, flags_) \
+      NS_STATIC_ATOM_ENUM(name_)
+    #include "nsCSSPseudoElementList.h"
+    #undef CSS_PSEUDO_ELEMENT
+    AtomsCount
+  };
+
+  const nsICSSPseudoElement mAtoms[static_cast<size_t>(Atoms::AtomsCount)];
 };
 
 extern const CSSPseudoElementAtoms gCSSPseudoElementAtoms;
 
 } // namespace detail
 
 } // namespace mozilla
 
-// Empty class derived from nsAtom so that function signatures can
-// require an atom from this atom list.
-class nsICSSPseudoElement : public nsAtom {};
-
 class nsCSSPseudoElements
 {
   typedef mozilla::CSSPseudoElementType Type;
   typedef mozilla::CSSEnabledState EnabledState;
 
 public:
   static void RegisterStaticAtoms();
 
@@ -119,20 +131,26 @@ public:
   // This must match EAGER_PSEUDO_COUNT in Rust code.
   static const size_t kEagerPseudoCount = 4;
 
   static bool IsEagerlyCascadedInServo(const Type aType)
   {
     return PseudoElementHasFlags(aType, CSS_PSEUDO_ELEMENT_IS_CSS2);
   }
 
-#define CSS_PSEUDO_ELEMENT(name_, value_, flags_) \
-  NS_STATIC_ATOM_SUBCLASS_DECL_PTR(nsICSSPseudoElement, name_)
-#include "nsCSSPseudoElementList.h"
-#undef CSS_PSEUDO_ELEMENT
+private:
+  static const nsStaticAtom* const sAtoms;
+  static constexpr size_t sAtomsLen =
+    mozilla::ArrayLength(mozilla::detail::gCSSPseudoElementAtoms.mAtoms);
+
+public:
+  #define CSS_PSEUDO_ELEMENT(name_, value_, flags_) \
+    NS_STATIC_ATOM_DECL_PTR(nsICSSPseudoElement, name_);
+  #include "nsCSSPseudoElementList.h"
+  #undef CSS_PSEUDO_ELEMENT
 
   static Type GetPseudoType(nsAtom* aAtom, EnabledState aEnabledState);
 
   // Get the atom for a given Type. aType must be < CSSPseudoElementType::Count.
   // This only ever returns static atoms, so it's fine to return a raw pointer.
   static nsAtom* GetPseudoAtom(Type aType);
 
   // Get the atom for a given pseudo-element string (e.g. "::before").  This can
--- a/layout/xul/nsMenuPopupFrame.cpp
+++ b/layout/xul/nsMenuPopupFrame.cpp
@@ -14,17 +14,16 @@
 #include "nsNameSpaceManager.h"
 #include "nsViewManager.h"
 #include "nsWidgetsCID.h"
 #include "nsMenuFrame.h"
 #include "nsMenuBarFrame.h"
 #include "nsPopupSetFrame.h"
 #include "nsPIDOMWindow.h"
 #include "nsIDOMEvent.h"
-#include "nsIDOMScreen.h"
 #include "nsIDOMXULMenuListElement.h"
 #include "nsIPresShell.h"
 #include "nsFrameManager.h"
 #include "nsIDocument.h"
 #include "nsRect.h"
 #include "nsIComponentManager.h"
 #include "nsBoxLayoutState.h"
 #include "nsIScrollableFrame.h"
--- a/parser/htmlparser/nsHTMLTags.cpp
+++ b/parser/htmlparser/nsHTMLTags.cpp
@@ -3,17 +3,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsHTMLTags.h"
 #include "nsCRT.h"
 #include "nsDataHashtable.h"
 #include "nsReadableUtils.h"
 #include "nsString.h"
-#include "nsStaticAtom.h"
 #include "nsUnicharUtils.h"
 #include "mozilla/HashFunctions.h"
 #include <algorithm>
 
 using namespace mozilla;
 
 // static array of unicode tag names
 #define HTML_TAG(_tag, _classname, _interfacename) (u"" #_tag),
--- a/parser/htmlparser/nsHTMLTags.h
+++ b/parser/htmlparser/nsHTMLTags.h
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 nsHTMLTags_h___
 #define nsHTMLTags_h___
 
-#include "nsStaticAtom.h"
 #include "nsString.h"
 #include "nsDataHashtable.h"
 #include "nsHashKeys.h"
 
 /*
    Declare the enum list using the magic of preprocessing
    enum values are "eHTMLTag_foo" (where foo is the tag)
 
--- a/xpcom/ds/nsAtomTable.cpp
+++ b/xpcom/ds/nsAtomTable.cpp
@@ -274,17 +274,17 @@ class nsAtomTable
 public:
   nsAtomSubTable& SelectSubTable(AtomTableKey& aKey);
   void AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, AtomsSizes& aSizes);
   void GC(GCKind aKind);
   already_AddRefed<nsAtom> Atomize(const nsAString& aUTF16String);
   already_AddRefed<nsAtom> Atomize(const nsACString& aUTF8String);
   already_AddRefed<nsAtom> AtomizeMainThread(const nsAString& aUTF16String);
   nsStaticAtom* GetStaticAtom(const nsAString& aUTF16String);
-  void RegisterStaticAtoms(const nsStaticAtomSetup* aSetup, uint32_t aCount);
+  void RegisterStaticAtoms(const nsStaticAtom* aAtoms, size_t aAtomsLen);
 
   // The result of this function may be imprecise if other threads are operating
   // on atoms concurrently. It's also slow, since it triggers a GC before
   // counting.
   size_t RacySlowCount();
 
   // This hash table op is a static member of this class so that it can take
   // advantage of |friend| declarations.
@@ -642,26 +642,23 @@ nsAtomSubTable::AddSizeOfExcludingThisLo
   aSizes.mTable += mTable.ShallowSizeOfExcludingThis(aMallocSizeOf);
   for (auto iter = mTable.Iter(); !iter.Done(); iter.Next()) {
     auto entry = static_cast<AtomTableEntry*>(iter.Get());
     entry->mAtom->AddSizeOfIncludingThis(aMallocSizeOf, aSizes);
   }
 }
 
 void
-nsAtomTable::RegisterStaticAtoms(const nsStaticAtomSetup* aSetup,
-                                 uint32_t aCount)
+nsAtomTable::RegisterStaticAtoms(const nsStaticAtom* aAtoms, size_t aAtomsLen)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_RELEASE_ASSERT(!gStaticAtomsDone, "Static atom insertion is finished!");
 
-  for (uint32_t i = 0; i < aCount; ++i) {
-    const nsStaticAtom* atom = aSetup[i].mAtom;
-    nsStaticAtom** atomp = aSetup[i].mAtomp;
-
+  for (uint32_t i = 0; i < aAtomsLen; ++i) {
+    const nsStaticAtom* atom = &aAtoms[i];
     MOZ_ASSERT(nsCRT::IsAscii(atom->String()));
     MOZ_ASSERT(NS_strlen(atom->String()) == atom->GetLength());
 
     AtomTableKey key(atom);
     nsAtomSubTable& table = SelectSubTable(key);
     MutexAutoLock lock(table.mLock);
     AtomTableEntry* he = table.Add(key);
 
@@ -671,25 +668,25 @@ nsAtomTable::RegisterStaticAtoms(const n
       // - Create a dynamic atom and then register a static atom with the same
       //   string while the dynamic atom is alive.
       // Both cases can cause subtle bugs, and are disallowed. We're
       // programming in C++ here, not Smalltalk.
       nsAutoCString name;
       he->mAtom->ToUTF8String(name);
       MOZ_CRASH_UNSAFE_PRINTF("Atom for '%s' already exists", name.get());
     }
-    he->mAtom = *atomp = const_cast<nsStaticAtom*>(atom);
+    he->mAtom = const_cast<nsStaticAtom*>(atom);
   }
 }
 
 void
-RegisterStaticAtoms(const nsStaticAtomSetup* aSetup, uint32_t aCount)
+NS_RegisterStaticAtoms(const nsStaticAtom* aAtoms, size_t aAtomsLen)
 {
   MOZ_ASSERT(gAtomTable);
-  gAtomTable->RegisterStaticAtoms(aSetup, aCount);
+  gAtomTable->RegisterStaticAtoms(aAtoms, aAtomsLen);
 }
 
 already_AddRefed<nsAtom>
 NS_Atomize(const char* aUTF8String)
 {
   MOZ_ASSERT(gAtomTable);
   return gAtomTable->Atomize(nsDependentCString(aUTF8String));
 }
--- a/xpcom/ds/nsGkAtoms.cpp
+++ b/xpcom/ds/nsGkAtoms.cpp
@@ -9,35 +9,34 @@
 namespace mozilla {
 namespace detail {
 
 MOZ_PUSH_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
 extern constexpr GkAtoms gGkAtoms = {
   #define GK_ATOM(name_, value_) NS_STATIC_ATOM_INIT_STRING(value_)
   #include "nsGkAtomList.h"
   #undef GK_ATOM
-
-  #define GK_ATOM(name_, value_) \
-    NS_STATIC_ATOM_INIT_ATOM(GkAtoms, name_, value_)
-  #include "nsGkAtomList.h"
-  #undef GK_ATOM
+  {
+    #define GK_ATOM(name_, value_) \
+      NS_STATIC_ATOM_INIT_ATOM(nsStaticAtom, GkAtoms, name_, value_)
+    #include "nsGkAtomList.h"
+    #undef GK_ATOM
+  }
 };
 MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
 
 } // namespace detail
 } // namespace mozilla
 
-#define GK_ATOM(name_, value_) NS_STATIC_ATOM_DEFN_PTR(nsGkAtoms, name_)
+const nsStaticAtom* const nsGkAtoms::sAtoms = mozilla::detail::gGkAtoms.mAtoms;
+
+#define GK_ATOM(name_, value_) \
+  NS_STATIC_ATOM_DEFN_PTR( \
+    nsStaticAtom, mozilla::detail::GkAtoms, mozilla::detail::gGkAtoms, \
+    nsGkAtoms, name_)
 #include "nsGkAtomList.h"
 #undef GK_ATOM
 
-static const nsStaticAtomSetup sGkAtomSetup[] = {
-  #define GK_ATOM(name_, value_) \
-    NS_STATIC_ATOM_SETUP(mozilla::detail::gGkAtoms, nsGkAtoms, name_)
-  #include "nsGkAtomList.h"
-  #undef GK_ATOM
-};
-
 void nsGkAtoms::RegisterStaticAtoms()
 {
-  NS_RegisterStaticAtoms(sGkAtomSetup);
+  NS_RegisterStaticAtoms(sAtoms, sAtomsLen);
 }
 
--- a/xpcom/ds/nsGkAtoms.h
+++ b/xpcom/ds/nsGkAtoms.h
@@ -14,29 +14,39 @@ namespace mozilla {
 namespace detail {
 
 struct GkAtoms
 {
   #define GK_ATOM(name_, value_) NS_STATIC_ATOM_DECL_STRING(name_, value_)
   #include "nsGkAtomList.h"
   #undef GK_ATOM
 
-  #define GK_ATOM(name_, value_) NS_STATIC_ATOM_DECL_ATOM(name_)
-  #include "nsGkAtomList.h"
-  #undef GK_ATOM
+  enum class Atoms {
+    #define GK_ATOM(name_, value_) NS_STATIC_ATOM_ENUM(name_)
+    #include "nsGkAtomList.h"
+    #undef GK_ATOM
+    AtomsCount
+  };
+
+  const nsStaticAtom mAtoms[static_cast<size_t>(Atoms::AtomsCount)];
 };
 
 extern const GkAtoms gGkAtoms;
 
 } // namespace detail
 } // namespace mozilla
 
 class nsGkAtoms
 {
+private:
+  static const nsStaticAtom* const sAtoms;
+  static constexpr size_t sAtomsLen =
+    mozilla::ArrayLength(mozilla::detail::gGkAtoms.mAtoms);
+
 public:
   static void RegisterStaticAtoms();
 
-  #define GK_ATOM(name_, value_) NS_STATIC_ATOM_DECL_PTR(name_)
+  #define GK_ATOM(name_, value_) NS_STATIC_ATOM_DECL_PTR(nsStaticAtom, name_)
   #include "nsGkAtomList.h"
   #undef GK_ATOM
 };
 
 #endif /* nsGkAtoms_h___ */
--- a/xpcom/ds/nsStaticAtom.h
+++ b/xpcom/ds/nsStaticAtom.h
@@ -4,245 +4,259 @@
  * 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 nsStaticAtom_h__
 #define nsStaticAtom_h__
 
 #include <stdint.h>
 #include "nsAtom.h"
+#include "mozilla/ArrayUtils.h"
 #include "mozilla/Maybe.h"
 
-// The following macros are used to define static atoms, typically in
-// conjunction with a .h file that defines the names and values of the atoms.
+// Static atoms are structured carefully to satisfy a lot of constraints.
+//
+// - We have ~2700 static atoms. They are divided across ~4 classes, with the
+//   majority in nsGkAtoms.
+//
+// - We want them to be constexpr so they end up in .rodata, and thus shared
+//   between processes, minimizing memory usage.
+//
+// - We need them to be in an array, so we can iterate over them (for
+//   registration and lookups).
+//
+// - Each static atom has a string literal associated with it. We can't use a
+//   pointer to the string literal because then the atoms won't end up in
+//   .rodata. Therefore the string literals and the atoms must be arranged in a
+//   way such that a numeric index can be used instead. This numeric index
+//   (nsStaticAtom::mStringOffset) must be computable at compile-time to keep
+//   the static atom constexpr. It should also not be too large (a uint32_t is
+//   reasonable).
+//
+// - Each static atom stores the hash value of its associated string literal;
+//   it's used in various ways. The hash value must be computed at
+//   compile-time, to keep the static atom constexpr.
+//
+// - As well as accessing each static atom via array indexing, we need an
+//   individual pointer, e.g. nsGkAtoms::foo. Ideally this would be constexpr
+//   so it doesn't take up any space in memory. Unfortunately MSVC's constexpr
+//   support is buggy and so this isn't possible yet. See bug 1449787.
+//
+// - The array of static atoms can't be in a .h file, because it's a huge
+//   constexpr expression, which would blow out compile times. But the
+//   individual pointers for the static atoms must be in a .h file so they are
+//   public.
+//
+// The macros below are used to define static atoms in a way that satisfies
+// these constraints. They are used in conjunction with a .h file that defines
+// the names and values of the atoms.
 //
 // For example, the .h file might be called MyAtomList.h and look like this:
 //
 //   MY_ATOM(one, "one")
 //   MY_ATOM(two, "two")
 //   MY_ATOM(three, "three")
 //
-// The code defining the static atoms should look something like this:
-//
-//   ====> MyAtoms.h <====
-//
-//   namespace detail {
-//
-//   struct MyAtoms
-//   {
-//     #define MY_ATOM(name_, value_) NS_STATIC_ATOM_DECL_STRING(name_, value_)
-//     #include "MyAtomList.h"
-//     #undef MY_ATOM
-//
-//     #define MY_ATOM(name_, value_) NS_STATIC_ATOM_DECL_ATOM(name_)
-//     #include "MyAtomList.h"
-//     #undef MY_ATOM
-//   };
-//
-//   extern const MyAtoms gMyAtoms;
-//
-//   } // namespace detail
-//
-//   class nsMyAtoms
-//   {
-//   public:
-//     #define MY_ATOM(name_, value_) NS_STATIC_ATOM_DECL_PTR(name_)
-//     #include "MyAtomList.h"
-//     #undef MY_ATOM
-//   };
-//
-//   ====> MyAtoms.cpp <====
-//
-//   MOZ_PUSH_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
-//   static constexpr MyAtoms gMyAtoms = {
-//     #define MY_ATOM(name_, value_) NS_STATIC_ATOM_INIT_STRING(value_)
-//     #include "MyAtomList.h"
-//     #undef MY_ATOM
-//
-//     #define MY_ATOM(name_, value_) NS_STATIC_ATOM_INIT_ATOM(MyAtoms, name_, value_)
-//     #include "MyAtomList.h"
-//     #undef MY_ATOM
-//   };
-//   MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
-//
-//   #define MY_ATOM(name_, value_) NS_STATIC_ATOM_DEFN_PTR(nsMyAtoms, name_)
-//   #include "MyAtomList.h"
-//   #undef MY_ATOM
-//
-//   static const nsStaticAtomSetup sMyAtomSetup[] = {
-//     #define MY_ATOM(name_, value_) NS_STATIC_ATOM_SETUP(mozilla::detail::gMyAtoms, nsMyAtoms, name_)
-//     #include "MyAtomList.h"
-//     #undef MY_ATOM
-//   };
-//
-// The macros expand to the following:
+// The code defining the static atoms should look something like the following.
+// ("<<<"/"---"/">>>" markers are used below to indicate what the macros look
+// like before and after expansion.)
 //
 //   ====> MyAtoms.h <====
 //
 //   // A `detail` namespace is used because the things within it aren't
 //   // directly referenced by external users of these static atoms.
 //   namespace detail {
 //
 //   // This `detail` class contains the atom strings and the atom objects.
 //   // Because they are together in a class, the mStringOffset field of the
 //   // atoms will be small and can be initialized at compile time.
 //   struct MyAtoms
 //   {
+//     <<<
+//     #define MY_ATOM(name_, value_) NS_STATIC_ATOM_DECL_STRING(name_, value_)
+//     #include "MyAtomList.h"
+//     #undef MY_ATOM
+//     ---
 //     const char16_t one_string[4];
 //     const char16_t two_string[4];
 //     const char16_t three_string[6];
+//     >>>
 //
-//     const nsStaticAtom one_atom;
-//     const nsStaticAtom two_atom;
-//     const nsStaticAtom three_atom;
+//     enum class Atoms {
+//       <<<
+//       #define MY_ATOM(name_, value_) NS_STATIC_ATOM_ENUM(name_)
+//       #include "MyAtomList.h"
+//       #undef MY_ATOM
+//       ---
+//       one,
+//       two,
+//       three,
+//       >>>
+//       AtomsCount
+//     };
+//
+//     const nsStaticAtom mAtoms[static_cast<size_t>(Atoms::AtomsCount)];
 //   };
 //
+//   // The MyAtoms instance is `extern const` so it can be defined in a .cpp
+//   // file.
 //   extern const MyAtoms gMyAtoms;
 //
 //   } // namespace detail
 //
 //   // This class holds the pointers to the individual atoms.
 //   class nsMyAtoms
 //   {
+//   private:
+//     // This is a useful handle to the array of atoms, used below and also
+//     // possibly by Rust code.
+//     static const nsStaticAtom* const sAtoms;
+//
+//     // The number of atoms, used below.
+//     static constexpr size_t sAtomsLen =
+//       mozilla::ArrayLength(detail::gMyAtoms.mAtoms);
+//
 //   public:
+//     // The type is not `nsStaticAtom* const` -- even though these atoms are
+//     // immutable -- because they are often passed to functions with
+//     // `nsAtom*` parameters, i.e. that can be passed both dynamic and
+//     // static.
+//     <<<
+//     #define MY_ATOM(name_, value_) NS_STATIC_ATOM_DECL_PTR(nsStaticAtom, name_)
+//     #include "MyAtomList.h"
+//     #undef MY_ATOM
+//     ---
 //     static nsStaticAtom* one;
 //     static nsStaticAtom* two;
 //     static nsStaticAtom* three;
+//     >>>
 //   };
 //
 //   ====> MyAtoms.cpp <====
 //
+//   namespace detail {
+//
 //   // Need to suppress some MSVC warning weirdness with WrappingMultiply().
 //   MOZ_PUSH_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
 //   // Because this is `constexpr` it ends up in read-only memory where it can
 //   // be shared between processes.
-//   extern constexpr MyAtoms gMyAtoms = {
+//   static constexpr MyAtoms gMyAtoms = {
+//     <<<
+//     #define MY_ATOM(name_, value_) NS_STATIC_ATOM_INIT_STRING(value_)
+//     #include "MyAtomList.h"
+//     #undef MY_ATOM
+//     ---
 //     u"one",
 //     u"two",
 //     u"three",
-//
-//     nsStaticAtom(u"one", 3, offsetof(MyAtoms, one_atom) -
-//                             offsetof(MyAtoms, one_string)),
-//     nsStaticAtom(u"two", 3, offsetof(MyAtoms, two_atom) -
-//                             offsetof(MyAtoms, two_string)),
-//     nsStaticAtom(u"three", 3, offsetof(MyAtoms, three_atom) -
-//                               offsetof(MyAtoms, three_string)),
+//     >>>
+//     {
+//       <<<
+//       #define MY_ATOM(name_, value_) NS_STATIC_ATOM_INIT_ATOM(nsStaticAtom, MyAtoms, name_, value_)
+//       #include "MyAtomList.h"
+//       #undef MY_ATOM
+//       ---
+//       nsStaticAtom(
+//         u"one", 3,
+//         offsetof(MyAtoms, mAtoms[static_cast<size_t>(MyAtoms::Atoms::one)]) -
+//         offsetof(MyAtoms, one_string)),
+//       nsStaticAtom(
+//         u"two", 3,
+//         offsetof(MyAtoms, mAtoms[static_cast<size_t>(MyAtoms::Atoms::two)]) -
+//         offsetof(MyAtoms, two_string)),
+//       nsStaticAtom(
+//         u"three", 3,
+//         offsetof(MyAtoms, mAtoms[static_cast<size_t>(MyAtoms::Atoms::three)]) -
+//         offsetof(MyAtoms, three_string)),
+//       >>>
+//     }
 //   };
 //   MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
 //
-//   nsStaticAtom* MyAtoms::one;
-//   nsStaticAtom* MyAtoms::two;
-//   nsStaticAtom* MyAtoms::three;
+//   } // namespace detail
+//
+//   const nsStaticAtom* const nsMyAtoms::sAtoms =
+//     mozilla::detail::gMyAtoms.mAtoms;
 //
-//   static const nsStaticAtomSetup sMyAtomSetup[] = {
-//     { &detail::gMyAtoms.one_atom, &nsMyAtoms::one },
-//     { &detail::gMyAtoms.two_atom, &nsMyAtoms::two },
-//     { &detail::gMyAtoms.three_atom, &nsMyAtoms::three },
-//   };
+//   <<<
+//   #define MY_ATOM(name_, value_) NS_STATIC_ATOM_DEFN_PTR(nsStaticAtom, detail::MyAtoms, detail::gMyAtoms, nsMyAtoms, name_)
+//   #include "MyAtomList.h"
+//   #undef MY_ATOM
+//   ---
+//   nsStaticAtom* nsMyAtoms::one =
+//     const_cast<nsStaticAtom*>(&detail::gMyAtoms.mAtoms[
+//       static_cast<size_t>(detail::MyAtoms::Atoms::one)]);
+//   nsStaticAtom* nsMyAtoms::two =
+//     const_cast<nsStaticAtom*>(&detail::gMyAtoms.mAtoms[
+//       static_cast<size_t>(detail::MyAtoms::Atoms::two)]);
+//   nsStaticAtom* nsMyAtoms::three =
+//     const_cast<nsStaticAtom*>(&detail::gMyAtoms.mAtoms[
+//       static_cast<size_t>(detail::MyAtoms::Atoms::three)]);
+//   >>>
 //
-// When RegisterStaticAtoms(sMyAtomSetup) is called it iterates over
-// sMyAtomSetup[]. E.g. for the first atom it does roughly the following:
-// - MyAtoms::one = one_atom
-// - inserts one_atom into the atom table
+// When NS_RegisterStaticAtoms(sAtoms, sAtomsLen) is called it iterates
+// over the atoms, inserting them into the atom table.
 
-// The declaration of the atom's string, which must be within the same `detail`
-// class as NS_STATIC_ATOM_DECL_ATOM.
+// The declaration of the atom's string.
 #define NS_STATIC_ATOM_DECL_STRING(name_, value_) \
   const char16_t name_##_string[sizeof(value_)];
 
-// The declaration of the static atom itself, which must be within the same
-// `detail` class as NS_STATIC_ATOM_DECL_STRING.
-#define NS_STATIC_ATOM_DECL_ATOM(name_) \
-  const nsStaticAtom name_##_atom;
+// The enum value for the atom.
+#define NS_STATIC_ATOM_ENUM(name_) \
+  name_,
 
-// The declaration of the pointer to the static atom, which must be within
-// a class.
-#define NS_STATIC_ATOM_DECL_PTR(name_) \
-  static nsStaticAtom* name_;
-
-// Like NS_STATIC_ATOM_DECL, but for sub-classes of nsStaticAtom.
-#define NS_STATIC_ATOM_SUBCLASS_DECL_PTR(type_, name_) \
+// The declaration of the pointer to the static atom. `type_` must be
+// `nsStaticAtom` or a subclass thereof.
+// XXX: Eventually this should be combined with NS_STATIC_ATOM_DEFN_PTR and the
+// pointer should be made `constexpr`. See bug 1449787.
+#define NS_STATIC_ATOM_DECL_PTR(type_, name_) \
   static type_* name_;
 
-// The initialization of the atom's string, which must be within a `constexpr`
-// instance of the `detail` class.
+// The initialization of the atom's string.
 #define NS_STATIC_ATOM_INIT_STRING(value_) \
   u"" value_,
 
-// The initialization of the static atom itself, which must be within a
-// `constexpr` instance of the `detail` class.
+// The initialization of the atom itself. `type_` must be `nsStaticAtom` or a
+// subclass thereof.
 //
 // Note that |value_| is an 8-bit string, and so |sizeof(value_)| is equal
 // to the number of chars (including the terminating '\0'). The |u""| prefix
 // converts |value_| to a 16-bit string.
-#define NS_STATIC_ATOM_INIT_ATOM(class_, name_, value_) \
-  nsStaticAtom(u"" value_, \
-               sizeof(value_) - 1, \
-               offsetof(class_, name_##_atom) - \
-               offsetof(class_, name_##_string)),
-
-// The definition of the pointer to the static atom. Initially null, it is
-// set by RegisterStaticAtoms() to point to a heap-allocated nsStaticAtom.
-#define NS_STATIC_ATOM_DEFN_PTR(class_, name_) \
-  nsStaticAtom* class_::name_;
-
-// Like NS_STATIC_ATOM_DEFN, but for sub-classes of nsStaticAtom.
-#define NS_STATIC_ATOM_SUBCLASS_DEFN_PTR(type_, class_, name_) \
-  type_* class_::name_;
+#define NS_STATIC_ATOM_INIT_ATOM(type_, detailClass_, name_, value_) \
+  type_(u"" value_, \
+        sizeof(value_) - 1, \
+        offsetof(detailClass_, \
+                 mAtoms[static_cast<size_t>(detailClass_::Atoms::name_)]) - \
+        offsetof(detailClass_, name_##_string)),
 
-// The StaticAtomSetup. Used during start-up, and in some cases afterwards.
-#define NS_STATIC_ATOM_SETUP(detailObj_, class_, name_) \
-  { &detailObj_.name_##_atom, &class_::name_ },
-
-// Like NS_STATIC_ATOM_SUBCLASS, but for sub-classes of nsStaticAtom.
-#define NS_STATIC_ATOM_SUBCLASS_SETUP(detailObj_, class_, name_) \
-  { &detailObj_.name_##_atom, \
-    reinterpret_cast<nsStaticAtom**>(&class_::name_) },
-
-// Holds data used to initialize large number of atoms during startup. Use
-// NS_STATIC_ATOM_SETUP to initialize these structs.
-struct nsStaticAtomSetup
-{
-  const nsStaticAtom* const mAtom;
-  nsStaticAtom** const mAtomp;
-};
+// Definition of the pointer to the static atom. `type_` must be `nsStaticAtom`
+// or a subclass thereof.
+#define NS_STATIC_ATOM_DEFN_PTR(type_, detailClass_, detailObj_, class_, name_) \
+  type_* class_::name_ = const_cast<type_*>( \
+    &detailObj_.mAtoms[static_cast<size_t>(detailClass_::Atoms::name_)]);
 
 // Register an array of static atoms with the atom table.
-template<uint32_t N>
 void
-NS_RegisterStaticAtoms(const nsStaticAtomSetup (&aSetup)[N])
-{
-  extern void RegisterStaticAtoms(const nsStaticAtomSetup* aSetup,
-                                  uint32_t aCount);
-  RegisterStaticAtoms(aSetup, N);
-}
+NS_RegisterStaticAtoms(const nsStaticAtom* aAtoms, size_t aAtomsLen);
 
 // This class holds basic operations on arrays of static atoms.
 class nsStaticAtomUtils {
 public:
-  template<uint32_t N>
-  static mozilla::Maybe<uint32_t> Lookup(nsAtom *aAtom,
-                                         const nsStaticAtomSetup (&aSetup)[N])
-  {
-    return Lookup(aAtom, aSetup, N);
-  }
-
-  template<uint32_t N>
-  static bool IsMember(nsAtom *aAtom, const nsStaticAtomSetup (&aSetup)[N])
-  {
-    return Lookup(aAtom, aSetup, N).isSome();
-  }
-
-private:
   static mozilla::Maybe<uint32_t> Lookup(nsAtom* aAtom,
-                                         const nsStaticAtomSetup* aSetup,
+                                         const nsStaticAtom* aAtoms,
                                          uint32_t aCount)
   {
     for (uint32_t i = 0; i < aCount; i++) {
-      if (aAtom == *(aSetup[i].mAtomp)) {
+      if (aAtom == &aAtoms[i]) {
         return mozilla::Some(i);
       }
     }
     return mozilla::Nothing();
   }
+
+  static bool IsMember(nsAtom* aAtom, const nsStaticAtom* aAtoms,
+                       uint32_t aCount)
+  {
+    return Lookup(aAtom, aAtoms, aCount).isSome();
+  }
 };
 
 #endif
--- a/xpcom/io/nsDirectoryService.cpp
+++ b/xpcom/io/nsDirectoryService.cpp
@@ -7,17 +7,16 @@
 #include "mozilla/ArrayUtils.h"
 
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 #include "nsDirectoryService.h"
 #include "nsLocalFile.h"
 #include "nsDebug.h"
 #include "nsGkAtoms.h"
-#include "nsStaticAtom.h"
 #include "nsEnumeratorUtils.h"
 
 #include "nsICategoryManager.h"
 #include "nsISimpleEnumerator.h"
 #include "nsIStringEnumerator.h"
 
 #if defined(XP_WIN)
 #include <windows.h>
@@ -98,56 +97,54 @@ nsDirectoryService::Create(nsISupports* 
 namespace mozilla {
 namespace detail {
 
 MOZ_PUSH_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
 extern constexpr DirectoryAtoms gDirectoryAtoms = {
   #define DIR_ATOM(name_, value_) NS_STATIC_ATOM_INIT_STRING(value_)
   #include "nsDirectoryServiceAtomList.h"
   #undef DIR_ATOM
-
-  #define DIR_ATOM(name_, value_) \
-    NS_STATIC_ATOM_INIT_ATOM(DirectoryAtoms, name_, value_)
-  #include "nsDirectoryServiceAtomList.h"
-  #undef DIR_ATOM
+  {
+    #define DIR_ATOM(name_, value_) \
+      NS_STATIC_ATOM_INIT_ATOM(nsStaticAtom, DirectoryAtoms, name_, value_)
+    #include "nsDirectoryServiceAtomList.h"
+    #undef DIR_ATOM
+  }
 };
 MOZ_POP_DISABLE_INTEGRAL_CONSTANT_OVERFLOW_WARNING
 
 } // namespace detail
 } // namespace mozilla
 
+const nsStaticAtom* const nsDirectoryService::sAtoms =
+  mozilla::detail::gDirectoryAtoms.mAtoms;
+
 #define DIR_ATOM(name_, value_) \
-  NS_STATIC_ATOM_DEFN_PTR(nsDirectoryService, name_)
+  NS_STATIC_ATOM_DEFN_PTR( \
+    nsStaticAtom, mozilla::detail::DirectoryAtoms, \
+    mozilla::detail::gDirectoryAtoms, nsDirectoryService, name_)
 #include "nsDirectoryServiceAtomList.h"
 #undef DIR_ATOM
 
-static const nsStaticAtomSetup sDirectoryServiceAtomSetup[] = {
-  #define DIR_ATOM(name_, value_) \
-    NS_STATIC_ATOM_SETUP( \
-      mozilla::detail::gDirectoryAtoms, nsDirectoryService, name_)
-  #include "nsDirectoryServiceAtomList.h"
-  #undef DIR_ATOM
-};
-
 NS_IMETHODIMP
 nsDirectoryService::Init()
 {
   NS_NOTREACHED("nsDirectoryService::Init() for internal use only!");
   return NS_OK;
 }
 
 void
 nsDirectoryService::RealInit()
 {
   NS_ASSERTION(!gService,
                "nsDirectoryService::RealInit Mustn't initialize twice!");
 
   gService = new nsDirectoryService();
 
-  NS_RegisterStaticAtoms(sDirectoryServiceAtomSetup);
+  NS_RegisterStaticAtoms(sAtoms, sAtomsLen);
 
   // Let the list hold the only reference to the provider.
   nsAppFileLocationProvider* defaultProvider = new nsAppFileLocationProvider;
   gService->mProviders.AppendElement(defaultProvider);
 }
 
 nsDirectoryService::~nsDirectoryService()
 {
--- a/xpcom/io/nsDirectoryService.h
+++ b/xpcom/io/nsDirectoryService.h
@@ -25,19 +25,24 @@ namespace mozilla {
 namespace detail {
 
 struct DirectoryAtoms
 {
   #define DIR_ATOM(name_, value_) NS_STATIC_ATOM_DECL_STRING(name_, value_)
   #include "nsDirectoryServiceAtomList.h"
   #undef DIR_ATOM
 
-  #define DIR_ATOM(name_, value_) NS_STATIC_ATOM_DECL_ATOM(name_)
-  #include "nsDirectoryServiceAtomList.h"
-  #undef DIR_ATOM
+  enum class Atoms {
+    #define DIR_ATOM(name_, value_) NS_STATIC_ATOM_ENUM(name_)
+    #include "nsDirectoryServiceAtomList.h"
+    #undef DIR_ATOM
+    AtomsCount
+  };
+
+  const nsStaticAtom mAtoms[static_cast<size_t>(Atoms::AtomsCount)];
 };
 
 extern const DirectoryAtoms gDirectoryAtoms;
 
 } // namespace detail
 } // namespace mozilla
 
 class nsDirectoryService final
@@ -69,15 +74,19 @@ public:
 private:
   ~nsDirectoryService();
 
   nsresult GetCurrentProcessDirectory(nsIFile** aFile);
 
   nsInterfaceHashtable<nsCStringHashKey, nsIFile> mHashtable;
   nsTArray<nsCOMPtr<nsIDirectoryServiceProvider>> mProviders;
 
+  static const nsStaticAtom* const sAtoms;
+  static constexpr size_t sAtomsLen =
+    mozilla::ArrayLength(mozilla::detail::gDirectoryAtoms.mAtoms);
+
 public:
-  #define DIR_ATOM(name_, value_) NS_STATIC_ATOM_DECL_PTR(name_)
+  #define DIR_ATOM(name_, value_) NS_STATIC_ATOM_DECL_PTR(nsStaticAtom, name_)
   #include "nsDirectoryServiceAtomList.h"
   #undef DIR_ATOM
 };
 
 #endif
--- a/xpcom/reflect/xptinfo/ShimInterfaceInfo.cpp
+++ b/xpcom/reflect/xptinfo/ShimInterfaceInfo.cpp
@@ -20,17 +20,16 @@
 #include "nsIDOMEventTarget.h"
 #include "nsIDOMGeoPositionError.h"
 #include "nsIDOMHTMLInputElement.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMNodeList.h"
 #include "nsIDOMOfflineResourceList.h"
 #include "nsIDOMParser.h"
 #include "nsIDOMRange.h"
-#include "nsIDOMScreen.h"
 #include "nsIDOMSerializer.h"
 #include "nsIDOMXMLDocument.h"
 #include "nsIDOMXULElement.h"
 #include "nsIListBoxObject.h"
 #include "nsIMessageManager.h"
 #include "nsISelection.h"
 #include "nsITreeBoxObject.h"
 #include "nsIWebBrowserPersistable.h"
@@ -64,17 +63,16 @@
 #include "mozilla/dom/NodeBinding.h"
 #include "mozilla/dom/EventBinding.h"
 #include "mozilla/dom/OfflineResourceListBinding.h"
 #include "mozilla/dom/PositionErrorBinding.h"
 #include "mozilla/dom/RangeBinding.h"
 #ifdef MOZ_WEBRTC
 #include "mozilla/dom/RTCDataChannelBinding.h"
 #endif
-#include "mozilla/dom/ScreenBinding.h"
 #include "mozilla/dom/SelectionBinding.h"
 #include "mozilla/dom/StorageEventBinding.h"
 #include "mozilla/dom/StyleSheetBinding.h"
 #include "mozilla/dom/StyleSheetListBinding.h"
 #include "mozilla/dom/SVGElementBinding.h"
 #include "mozilla/dom/TimeEventBinding.h"
 #include "mozilla/dom/TreeBoxObjectBinding.h"
 #include "mozilla/dom/XMLDocumentBinding.h"
@@ -153,17 +151,16 @@ const ComponentsInterfaceShimEntry kComp
   DEFINE_SHIM(NodeList),
   DEFINE_SHIM(Node),
   DEFINE_SHIM(OfflineResourceList),
   DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIDOMParser, DOMParser),
   DEFINE_SHIM(Range),
 #ifdef MOZ_WEBRTC
   DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIDOMDataChannel, RTCDataChannel),
 #endif
-  DEFINE_SHIM(Screen),
   DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIDOMSerializer, XMLSerializer),
   DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsITreeBoxObject, TreeBoxObject),
   DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIWebBrowserPersistable, FrameLoader),
   DEFINE_SHIM(XMLDocument),
   DEFINE_SHIM(XULElement),
   DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsISelection, Selection),
 };
 
--- a/xpcom/string/nsSubstring.cpp
+++ b/xpcom/string/nsSubstring.cpp
@@ -18,17 +18,16 @@
 #include <stdlib.h>
 #include "nsAString.h"
 #include "nsString.h"
 #include "nsStringBuffer.h"
 #include "nsDependentString.h"
 #include "nsPrintfCString.h"
 #include "nsMemory.h"
 #include "prprf.h"
-#include "nsStaticAtom.h"
 #include "nsCOMPtr.h"
 
 #include "mozilla/IntegerPrintfMacros.h"
 #ifdef XP_WIN
 #include <windows.h>
 #include <process.h>
 #define getpid() _getpid()
 #define pthread_self() GetCurrentThreadId()
--- a/xpcom/tests/gtest/TestAtoms.cpp
+++ b/xpcom/tests/gtest/TestAtoms.cpp
@@ -5,17 +5,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ArrayUtils.h"
 
 #include "nsAtom.h"
 #include "nsString.h"
 #include "UTFStrings.h"
 #include "nsIServiceManager.h"
-#include "nsStaticAtom.h"
 #include "nsThreadUtils.h"
 
 #include "gtest/gtest.h"
 
 using namespace mozilla;
 
 int32_t NS_GetUnusedAtomCount(void);
 
--- a/xpfe/appshell/nsXULWindow.cpp
+++ b/xpfe/appshell/nsXULWindow.cpp
@@ -15,26 +15,27 @@
 #include "nsString.h"
 #include "nsWidgetsCID.h"
 #include "nsThreadUtils.h"
 #include "nsNetCID.h"
 #include "nsQueryObject.h"
 #include "mozilla/Sprintf.h"
 
 //Interfaces needed to be included
+#include "nsGlobalWindowOuter.h"
 #include "nsIAppShell.h"
 #include "nsIAppShellService.h"
 #include "nsIServiceManager.h"
 #include "nsIContentViewer.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMXULElement.h"
 #include "nsPIDOMWindow.h"
-#include "nsIDOMScreen.h"
+#include "nsScreen.h"
 #include "nsIEmbeddingSiteWindow.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIIOService.h"
 #include "nsILoadContext.h"
 #include "nsIObserverService.h"
 #include "nsIWindowMediator.h"
 #include "nsIScreenManager.h"
@@ -1023,33 +1024,35 @@ NS_IMETHODIMP nsXULWindow::EnsureAuthPro
     if (wwatch)
       wwatch->GetNewAuthPrompter(ourWindow, getter_AddRefs(mAuthPrompter));
   }
   return mAuthPrompter ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP nsXULWindow::GetAvailScreenSize(int32_t* aAvailWidth, int32_t* aAvailHeight)
 {
-  nsresult rv;
-
   nsCOMPtr<mozIDOMWindowProxy> domWindow;
   GetWindowDOMWindow(getter_AddRefs(domWindow));
   NS_ENSURE_STATE(domWindow);
 
-  auto* window = nsPIDOMWindowOuter::From(domWindow);
-  NS_ENSURE_STATE(window);
+  auto* window = nsGlobalWindowOuter::Cast(domWindow);
 
-  nsCOMPtr<nsIDOMScreen> screen = window->GetScreen();
+  RefPtr<nsScreen> screen = window->GetScreen();
   NS_ENSURE_STATE(screen);
 
-  rv = screen->GetAvailWidth(aAvailWidth);
-  NS_ENSURE_SUCCESS(rv, rv);
+  ErrorResult rv;
+  *aAvailWidth = screen->GetAvailWidth(rv);
+  if (NS_WARN_IF(rv.Failed())) {
+    return rv.StealNSResult();
+  }
 
-  rv = screen->GetAvailHeight(aAvailHeight);
-  NS_ENSURE_SUCCESS(rv, rv);
+  *aAvailHeight = screen->GetAvailHeight(rv);
+  if (NS_WARN_IF(rv.Failed())) {
+    return rv.StealNSResult();
+  }
 
   return NS_OK;
 }
 
 // Rounds window size to 1000x1000, or, if there isn't enough available
 // screen space, to a multiple of 200x100.
 NS_IMETHODIMP nsXULWindow::ForceRoundedDimensions()
 {