Merge inbound to mozilla-central. a=merge
authorarthur.iakab <aiakab@mozilla.com>
Tue, 03 Apr 2018 12:31:23 +0300
changeset 776583 4a3275936ddf871103b53e00608e2b8d5aee7e69
parent 776578 2ee160335e150f20df3471b60b5e58ce873e2ff6 (current diff)
parent 776582 efce674123ace94d821157b996f0d5caa7380620 (diff)
child 776584 c3d9526987c9a20d35a41f84207282d43ddac556
child 776602 bdfb459d10bcf75faa6c5a37c5d0684e233d317f
child 776607 be1b1784f539190e7df0161f2d45db0cb4a935fe
child 776619 99a953f1823fcf96d6f312b356a11f245a9b0c78
child 776637 63cc0f7b07620ae58a78c500400cf8b1f4d13730
child 776638 0fb749c264b2b2575d4de1ed2a1fcb626b514389
child 776651 ef74bae40f890bb27734b570cb4daccf8b065cc2
child 776652 250aecba4ab1504472d3ab9a58cb393e8ec506c8
child 776661 ddbc9afef1cf28d5e0736f0ad760ec19d2d2946c
child 776663 fae065d4d6a4ea3535518c5eeafc0dd381802ac3
child 776668 2ee0df71b1658c9c8e32048255c7b778f5a2127a
child 776685 ff254e48d66d979478f8d4dcdce48a534f4b3d92
child 776692 394da391d93db45abea0fd1b902da1a59b534dc5
child 776748 5ec55f7a95f94cf39d57cdf36abecab914ea48eb
child 776750 72fd006ddd5221a43e8114f5248c8f5c252b5338
child 776760 ac2727f5e49f946650e3d860a38bc5db96f15adc
child 776761 96eef1087baa4b59f270b75841a83bebbb25eb47
child 776762 ef81aa97d855d584183b34d12592a27aa8fd1af5
child 776803 9d6678d692a0a5a36274f187ba783d393f4f2231
child 776834 36947c14d3235576ad3c0f9c4f9848d85ccf8a41
child 776875 e270ca9aacafd45da6de7f7f0030ede4a64de3fe
child 776901 801d1d90b2ffcca423d9cee10509169318890b8c
child 776957 39224525e68bc1076ca972d5a6423dc4d0e33980
child 777061 724eb7670eb4e4e455f8ca6dba9ac4aeae8e7d09
child 777112 d366ba19f2bd9bd0e94234dc4f41b906865db4f9
child 777188 32bfe3fdd57e8a81f5cfc6850e1ff34ebe0f6427
child 777198 94fa671daffff7d0fb21d90e863a45a2c13f4188
child 777199 2f0d772b4eac47ecb43429d28f0b2e8c0dae4d06
child 777204 cc07dce567e1b7ce47772a2a056b52510c00ef88
child 777325 e502789f405894584efc1aa582f81bb3798e0d43
child 777370 90ac3edadaec50f2509e1c36dc8d9134ef73e10e
child 777378 5a22f6d0a995303e6a4039eafc056631fbb86415
child 777456 f99f8528d1a43825fc14c172ab3375b2db697455
child 777504 63fafaa6595dd261804b71811f1504f55ec2ef28
child 778365 a444b9258c2215265d5ca013376335401968d446
child 778507 bbb993644358b6a281a110cadcc6839bd548218c
child 778532 8ace795a9db2159bb76dfa1c8b6ddc0dae0a4ac8
child 778552 3d299268a1ad7d002c9d2654eb63c71eee3998e1
child 779819 67fd288b4455ad3f4146fff04d410b5e5106b3fd
child 779820 788a11557ac5985eab3e9c8e1b52e1adbf89ef2d
child 780695 131c24a1e6e1f3ba0c2f31c7d46c80722377868d
push id104907
push userbmo:ato@sny.no
push dateTue, 03 Apr 2018 10:28:20 +0000
reviewersmerge
milestone61.0a1
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()
 {