Bug 1559546 - Use atoms for grid line names. r=mats
authorEmilio Cobos Álvarez <emilio@crisal.io>
Wed, 19 Jun 2019 05:58:11 +0000
changeset 479182 acf98e967abe248d16574757806f3a0f68579d3f
parent 479181 1e5b608b1442186062fe53640bfdff7b34227883
child 479183 8567a308ac7a8e2087903aedd1d92032c9c7eb60
push id113467
push userrgurzau@mozilla.com
push dateWed, 19 Jun 2019 15:55:23 +0000
treeherdermozilla-inbound@10e3ed789e2b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmats
bugs1559546
milestone69.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1559546 - Use atoms for grid line names. r=mats The style system already atomizes all CustomIdent values, which means that we're just wasting memory and CPU by doing string copies all over the place. This patch fixes it. This also simplifies further changes to use as much of the rust data structures as possible. I had to switch from nsTHashtable to mozilla::HashTable because the former doesn't handle well non-default-constructible structs (like NamedLine, which now has a StyleAtom, which is not default-constructible). Differential Revision: https://phabricator.services.mozilla.com/D35119
dom/grid/Grid.cpp
dom/grid/GridArea.cpp
dom/grid/GridArea.h
dom/grid/GridLine.cpp
dom/grid/GridLine.h
dom/grid/GridLines.cpp
dom/grid/GridLines.h
layout/generic/nsGridContainerFrame.cpp
layout/generic/nsGridContainerFrame.h
layout/style/GeckoBindings.cpp
layout/style/GeckoBindings.h
layout/style/nsComputedDOMStyle.cpp
layout/style/nsComputedDOMStyle.h
layout/style/nsStyleStruct.h
servo/components/style/properties/gecko.mako.rs
servo/components/style/values/specified/position.rs
servo/ports/geckolib/glue.rs
--- a/dom/grid/Grid.cpp
+++ b/dom/grid/Grid.cpp
@@ -29,39 +29,39 @@ Grid::Grid(nsISupports* aParent, nsGridC
   MOZ_ASSERT(aFrame,
              "Should never be instantiated with a null nsGridContainerFrame");
 
   // Construct areas first, because lines may need to reference them
   // to extract additional names for boundary lines.
 
   // Add implicit areas first. Track the names that we add here, because
   // we will ignore future explicit areas with the same name.
-  nsTHashtable<nsCStringHashKey> namesSeen;
+  nsTHashtable<nsRefPtrHashKey<nsAtom>> namesSeen;
   nsGridContainerFrame::ImplicitNamedAreas* implicitAreas =
       aFrame->GetImplicitNamedAreas();
   if (implicitAreas) {
-    for (auto iter = implicitAreas->Iter(); !iter.Done(); iter.Next()) {
-      auto& areaInfo = iter.Data();
-      namesSeen.PutEntry(areaInfo.name.AsString());
-      GridArea* area = new GridArea(
-          this, areaInfo.name.AsString(), GridDeclaration::Implicit,
-          areaInfo.rows.start, areaInfo.rows.end, areaInfo.columns.start,
-          areaInfo.columns.end);
+    for (auto iter = implicitAreas->iter(); !iter.done(); iter.next()) {
+      auto& areaInfo = iter.get().value();
+      namesSeen.PutEntry(areaInfo.name.AsAtom());
+      GridArea* area =
+          new GridArea(this, areaInfo.name.AsAtom(), GridDeclaration::Implicit,
+                       areaInfo.rows.start, areaInfo.rows.end,
+                       areaInfo.columns.start, areaInfo.columns.end);
       mAreas.AppendElement(area);
     }
   }
 
   // Add explicit areas next, as long as they don't have the same name
   // as the implicit areas, because the implicit values override what was
   // initially available in the explicit areas.
   if (auto* explicitAreas = aFrame->GetExplicitNamedAreas()) {
     for (auto& areaInfo : explicitAreas->AsSpan()) {
-      if (!namesSeen.Contains(areaInfo.name.AsString())) {
+      if (!namesSeen.Contains(areaInfo.name.AsAtom())) {
         GridArea* area = new GridArea(
-            this, areaInfo.name.AsString(), GridDeclaration::Explicit,
+            this, areaInfo.name.AsAtom(), GridDeclaration::Explicit,
             areaInfo.rows.start, areaInfo.rows.end, areaInfo.columns.start,
             areaInfo.columns.end);
         mAreas.AppendElement(area);
       }
     }
   }
 
   // Now construct the tracks and lines.
--- a/dom/grid/GridArea.cpp
+++ b/dom/grid/GridArea.cpp
@@ -14,39 +14,35 @@ namespace dom {
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(GridArea, mParent)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(GridArea)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(GridArea)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(GridArea)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
-GridArea::GridArea(Grid* aParent, const nsDependentCSubstring& aName,
-                   GridDeclaration aType, uint32_t aRowStart, uint32_t aRowEnd,
-                   uint32_t aColumnStart, uint32_t aColumnEnd)
+GridArea::GridArea(Grid* aParent, nsAtom* aName, GridDeclaration aType,
+                   uint32_t aRowStart, uint32_t aRowEnd, uint32_t aColumnStart,
+                   uint32_t aColumnEnd)
     : mParent(aParent),
       mName(aName),
       mType(aType),
       mRowStart(aRowStart),
       mRowEnd(aRowEnd),
       mColumnStart(aColumnStart),
       mColumnEnd(aColumnEnd) {}
 
 GridArea::~GridArea() {}
 
 JSObject* GridArea::WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto) {
   return GridArea_Binding::Wrap(aCx, this, aGivenProto);
 }
 
-void GridArea::GetName(nsCString& aName) const { aName = mName; }
-
-void GridArea::GetName(nsString& aName) const {
-  aName = NS_ConvertUTF8toUTF16(mName);
-}
+void GridArea::GetName(nsString& aName) const { mName->ToString(aName); }
 
 GridDeclaration GridArea::Type() const { return mType; }
 
 uint32_t GridArea::RowStart() const { return mRowStart; }
 
 uint32_t GridArea::RowEnd() const { return mRowEnd; }
 
 uint32_t GridArea::ColumnStart() const { return mColumnStart; }
--- a/dom/grid/GridArea.h
+++ b/dom/grid/GridArea.h
@@ -12,42 +12,41 @@
 
 namespace mozilla {
 namespace dom {
 
 class Grid;
 
 class GridArea : public nsISupports, public nsWrapperCache {
  public:
-  explicit GridArea(Grid* aParent, const nsDependentCSubstring& aName,
-                    GridDeclaration aType, uint32_t aRowStart, uint32_t aRowEnd,
-                    uint32_t aColumnStart, uint32_t aColumnEnd);
+  explicit GridArea(Grid* aParent, nsAtom* aName, GridDeclaration aType,
+                    uint32_t aRowStart, uint32_t aRowEnd, uint32_t aColumnStart,
+                    uint32_t aColumnEnd);
 
  protected:
   virtual ~GridArea();
 
  public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(GridArea)
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto) override;
   Grid* GetParentObject() { return mParent; }
 
-  void GetName(nsCString& aName) const;
   void GetName(nsString& aName) const;
   GridDeclaration Type() const;
   uint32_t RowStart() const;
   uint32_t RowEnd() const;
   uint32_t ColumnStart() const;
   uint32_t ColumnEnd() const;
 
  protected:
   RefPtr<Grid> mParent;
-  const nsCString mName;
+  const RefPtr<nsAtom> mName;
   const GridDeclaration mType;
   const uint32_t mRowStart;
   const uint32_t mRowEnd;
   const uint32_t mColumnStart;
   const uint32_t mColumnEnd;
 };
 
 }  // namespace dom
--- a/dom/grid/GridLine.cpp
+++ b/dom/grid/GridLine.cpp
@@ -27,21 +27,20 @@ GridLine::GridLine(GridLines* aParent)
       mType(GridDeclaration::Implicit),
       mNumber(0),
       mNegativeNumber(0) {
   MOZ_ASSERT(aParent, "Should never be instantiated with a null GridLines");
 }
 
 GridLine::~GridLine() {}
 
-void GridLine::GetNames(nsTArray<nsCString>& aNames) const { aNames = mNames; }
 void GridLine::GetNames(nsTArray<nsString>& aNames) const {
   aNames.SetCapacity(mNames.Length());
   for (auto& name : mNames) {
-    aNames.AppendElement(NS_ConvertUTF8toUTF16(name));
+    aNames.AppendElement(nsDependentAtomString(name));
   }
 }
 
 JSObject* GridLine::WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto) {
   return GridLine_Binding::Wrap(aCx, this, aGivenProto);
 }
 
@@ -50,25 +49,25 @@ double GridLine::Start() const { return 
 double GridLine::Breadth() const { return mBreadth; }
 
 GridDeclaration GridLine::Type() const { return mType; }
 
 uint32_t GridLine::Number() const { return mNumber; }
 
 int32_t GridLine::NegativeNumber() const { return mNegativeNumber; }
 
-void GridLine::SetLineValues(const nsTArray<nsCString>& aNames, double aStart,
-                             double aBreadth, uint32_t aNumber,
+void GridLine::SetLineValues(const nsTArray<RefPtr<nsAtom>>& aNames,
+                             double aStart, double aBreadth, uint32_t aNumber,
                              int32_t aNegativeNumber, GridDeclaration aType) {
   mNames = aNames;
   mStart = aStart;
   mBreadth = aBreadth;
   mNumber = aNumber;
   mNegativeNumber = aNegativeNumber;
   mType = aType;
 }
 
-void GridLine::SetLineNames(const nsTArray<nsCString>& aNames) {
+void GridLine::SetLineNames(const nsTArray<RefPtr<nsAtom>>& aNames) {
   mNames = aNames;
 }
 
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/grid/GridLine.h
+++ b/dom/grid/GridLine.h
@@ -23,38 +23,38 @@ class GridLine : public nsISupports, pub
 
  protected:
   virtual ~GridLine();
 
  public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(GridLine)
 
-  void GetNames(nsTArray<nsCString>& aNames) const;
   void GetNames(nsTArray<nsString>& aNames) const;
+  const nsTArray<RefPtr<nsAtom>>& Names() const { return mNames; }
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto) override;
   GridLines* GetParentObject() { return mParent; }
 
   double Start() const;
   double Breadth() const;
   GridDeclaration Type() const;
   uint32_t Number() const;
   int32_t NegativeNumber() const;
 
-  void SetLineValues(const nsTArray<nsCString>& aNames, double aStart,
+  void SetLineValues(const nsTArray<RefPtr<nsAtom>>& aNames, double aStart,
                      double aBreadth, uint32_t aNumber, int32_t aNegativeNumber,
                      GridDeclaration aType);
 
-  void SetLineNames(const nsTArray<nsCString>& aNames);
+  void SetLineNames(const nsTArray<RefPtr<nsAtom>>& aNames);
 
  protected:
   RefPtr<GridLines> mParent;
-  nsTArray<nsCString> mNames;
+  nsTArray<RefPtr<nsAtom>> mNames;
   double mStart;
   double mBreadth;
   GridDeclaration mType;
   uint32_t mNumber;
   int32_t mNegativeNumber;
 };
 
 }  // namespace dom
--- a/dom/grid/GridLines.cpp
+++ b/dom/grid/GridLines.cpp
@@ -43,25 +43,25 @@ GridLine* GridLines::Item(uint32_t aInde
 GridLine* GridLines::IndexedGetter(uint32_t aIndex, bool& aFound) {
   aFound = aIndex < mLines.Length();
   if (!aFound) {
     return nullptr;
   }
   return mLines[aIndex];
 }
 
-static void AddLineNameIfNotPresent(nsTArray<nsCString>& aLineNames,
-                                    const nsCString& aName) {
+static void AddLineNameIfNotPresent(nsTArray<RefPtr<nsAtom>>& aLineNames,
+                                    nsAtom* aName) {
   if (!aLineNames.Contains(aName)) {
     aLineNames.AppendElement(aName);
   }
 }
 
-static void AddLineNamesIfNotPresent(nsTArray<nsCString>& aLineNames,
-                                     const nsTArray<nsCString>& aNames) {
+static void AddLineNamesIfNotPresent(nsTArray<RefPtr<nsAtom>>& aLineNames,
+                                     const nsTArray<RefPtr<nsAtom>>& aNames) {
   for (const auto& name : aNames) {
     AddLineNameIfNotPresent(aLineNames, name);
   }
 }
 
 void GridLines::SetLineInfo(const ComputedGridTrackInfo* aTrackInfo,
                             const ComputedGridLineInfo* aLineInfo,
                             const nsTArray<RefPtr<GridArea>>& aAreas,
@@ -112,34 +112,34 @@ void GridLines::SetLineInfo(const Comput
 
       // Get the line names for the current line. aLineInfo->mNames
       // may contain duplicate names. This is intentional, since grid
       // layout works fine with duplicate names, and we don't want to
       // detect and remove duplicates in layout since it is an O(n^2)
       // problem. We do the work here since this is only run when
       // requested by devtools, and slowness here will not affect
       // normal browsing.
-      const nsTArray<nsCString>& possiblyDuplicateLineNames(
-          aLineInfo->mNames.SafeElementAt(i, nsTArray<nsCString>()));
+      const nsTArray<RefPtr<nsAtom>>& possiblyDuplicateLineNames(
+          aLineInfo->mNames.SafeElementAt(i, nsTArray<RefPtr<nsAtom>>()));
 
-      nsTArray<nsCString> lineNames;
+      nsTArray<RefPtr<nsAtom>> lineNames;
       AddLineNamesIfNotPresent(lineNames, possiblyDuplicateLineNames);
 
       // Add in names from grid areas where this line is used as a boundary.
       for (auto area : aAreas) {
         // We specifically ignore line names from implicitly named areas,
         // because it can be confusing for designers who might naturally use
         // a named line of "-start" or "-end" and create an implicit named
         // area without meaning to.
         if (area->Type() == GridDeclaration::Implicit) {
           continue;
         }
 
         bool haveNameToAdd = false;
-        nsAutoCString nameToAdd;
+        nsAutoString nameToAdd;
         area->GetName(nameToAdd);
         if (aIsRow) {
           if (area->RowStart() == line1Index) {
             haveNameToAdd = true;
             nameToAdd.AppendLiteral("-start");
           } else if (area->RowEnd() == line1Index) {
             haveNameToAdd = true;
             nameToAdd.AppendLiteral("-end");
@@ -150,17 +150,18 @@ void GridLines::SetLineInfo(const Comput
             nameToAdd.AppendLiteral("-start");
           } else if (area->ColumnEnd() == line1Index) {
             haveNameToAdd = true;
             nameToAdd.AppendLiteral("-end");
           }
         }
 
         if (haveNameToAdd) {
-          AddLineNameIfNotPresent(lineNames, nameToAdd);
+          RefPtr<nsAtom> name = NS_Atomize(nameToAdd);
+          AddLineNameIfNotPresent(lineNames, name);
         }
       }
 
       if (i >= (aTrackInfo->mRepeatFirstTrack +
                 aTrackInfo->mNumLeadingImplicitTracks) &&
           repeatIndex < numRepeatTracks) {
         numAddedLines += AppendRemovedAutoFits(
             aTrackInfo, aLineInfo, lastTrackEdge, repeatIndex, numRepeatTracks,
@@ -245,71 +246,70 @@ void GridLines::SetLineInfo(const Comput
 
         // If both start and end indexes are -1, then stop here since we cannot
         // reason about the naming for either lines.
         if (startIndex < 0 && endIndex < 0) {
           break;
         }
 
         // Get the "-start" and "-end" line names of the grid area.
-        nsAutoCString startLineName;
+        nsAutoString startLineName;
         area->GetName(startLineName);
         startLineName.AppendLiteral("-start");
-        nsAutoCString endLineName;
+        nsAutoString endLineName;
         area->GetName(endLineName);
         endLineName.AppendLiteral("-end");
 
         // Get the list of existing line names for the start and end of the grid
         // area. In the case where one of the start or end indexes are -1, use a
         // dummy line as a substitute for the start/end line.
         RefPtr<GridLine> dummyLine = new GridLine(this);
         RefPtr<GridLine> areaStartLine =
             startIndex > -1 ? mLines[startIndex] : dummyLine;
-        nsTArray<nsCString> startLineNames;
-        areaStartLine->GetNames(startLineNames);
+        nsTArray<RefPtr<nsAtom>> startLineNames(areaStartLine->Names());
 
         RefPtr<GridLine> areaEndLine =
             endIndex > -1 ? mLines[endIndex] : dummyLine;
-        nsTArray<nsCString> endLineNames;
-        areaEndLine->GetNames(endLineNames);
+        nsTArray<RefPtr<nsAtom>> endLineNames(areaEndLine->Names());
 
-        if (startLineNames.Contains(endLineName) ||
-            endLineNames.Contains(startLineName)) {
+        RefPtr<nsAtom> start = NS_Atomize(startLineName);
+        RefPtr<nsAtom> end = NS_Atomize(endLineName);
+        if (startLineNames.Contains(end) || endLineNames.Contains(start)) {
           // Add the reversed line names.
-          AddLineNameIfNotPresent(startLineNames, endLineName);
-          AddLineNameIfNotPresent(endLineNames, startLineName);
+          AddLineNameIfNotPresent(startLineNames, end);
+          AddLineNameIfNotPresent(endLineNames, start);
         } else {
           // Add the normal line names.
-          AddLineNameIfNotPresent(startLineNames, startLineName);
-          AddLineNameIfNotPresent(endLineNames, endLineName);
+          AddLineNameIfNotPresent(startLineNames, start);
+          AddLineNameIfNotPresent(endLineNames, end);
         }
 
         areaStartLine->SetLineNames(startLineNames);
         areaEndLine->SetLineNames(endLineNames);
       }
     }
   }
 }
 
 uint32_t GridLines::AppendRemovedAutoFits(
     const ComputedGridTrackInfo* aTrackInfo,
     const ComputedGridLineInfo* aLineInfo, nscoord aLastTrackEdge,
     uint32_t& aRepeatIndex, uint32_t aNumRepeatTracks,
-    uint32_t aNumLeadingTracks, nsTArray<nsCString>& aLineNames) {
+    uint32_t aNumLeadingTracks, nsTArray<RefPtr<nsAtom>>& aLineNames) {
   // Check to see if lineNames contains ALL of the before line names.
   bool alreadyHasBeforeLineNames = true;
   for (const auto& beforeName : aLineInfo->mNamesBefore) {
     if (!aLineNames.Contains(beforeName)) {
       alreadyHasBeforeLineNames = false;
       break;
     }
   }
 
   bool extractedExplicitLineNames = false;
-  nsTArray<nsCString> explicitLineNames;
+  nsTArray<RefPtr<nsAtom>> explicitLineNames;
   uint32_t linesAdded = 0;
   while (aRepeatIndex < aNumRepeatTracks &&
          aTrackInfo->mRemovedRepeatTracks[aRepeatIndex]) {
     // If this is not the very first call to this function, and if we
     // haven't already added a line this call, pull all the explicit
     // names to pass along to the next line that will be added after
     // this function completes.
     if (aRepeatIndex > 0 && linesAdded == 0) {
--- a/dom/grid/GridLines.h
+++ b/dom/grid/GridLines.h
@@ -6,16 +6,18 @@
 
 #ifndef mozilla_dom_GridLines_h
 #define mozilla_dom_GridLines_h
 
 #include "nsCoord.h"
 #include "nsTArray.h"
 #include "nsWrapperCache.h"
 
+class nsAtom;
+
 namespace mozilla {
 
 struct ComputedGridTrackInfo;
 struct ComputedGridLineInfo;
 
 namespace dom {
 
 class GridDimension;
@@ -46,17 +48,17 @@ class GridLines : public nsISupports, pu
                    const nsTArray<RefPtr<GridArea>>& aAreas, bool aIsRow);
 
  protected:
   uint32_t AppendRemovedAutoFits(const ComputedGridTrackInfo* aTrackInfo,
                                  const ComputedGridLineInfo* aLineInfo,
                                  nscoord aLastTrackEdge, uint32_t& aRepeatIndex,
                                  uint32_t aNumRepeatTracks,
                                  uint32_t aNumLeadingTracks,
-                                 nsTArray<nsCString>& aLineNames);
+                                 nsTArray<RefPtr<nsAtom>>& aLineNames);
 
   RefPtr<GridDimension> mParent;
   nsTArray<RefPtr<GridLine>> mLines;
 };
 
 }  // namespace dom
 }  // namespace mozilla
 
--- a/layout/generic/nsGridContainerFrame.cpp
+++ b/layout/generic/nsGridContainerFrame.cpp
@@ -936,19 +936,20 @@ class MOZ_STACK_CLASS nsGridContainerFra
    *
    * E.g. to search for "A 2" forward from the start of the grid: aName is "A"
    * aNth is 2 and aFromIndex is zero.  To search for "A -2", aNth is -2 and
    * aFromIndex is ExplicitGridEnd + 1 (which is the line "before" the last
    * line when we're searching in reverse).  For "span A 2", aNth is 2 when
    * used on a grid-[row|column]-end property and -2 for a *-start property,
    * and aFromIndex is the line (which we should skip) on the opposite property.
    */
-  uint32_t FindNamedLine(const nsCString& aName, int32_t* aNth,
-                         uint32_t aFromIndex,
+  uint32_t FindNamedLine(nsAtom* aName, int32_t* aNth, uint32_t aFromIndex,
                          const nsTArray<uint32_t>& aImplicitLines) const {
+    MOZ_ASSERT(aName);
+    MOZ_ASSERT(aName != nsGkAtoms::_empty);
     MOZ_ASSERT(aNth && *aNth != 0);
     if (*aNth > 0) {
       return FindLine(aName, aNth, aFromIndex, aImplicitLines);
     }
     int32_t nth = -*aNth;
     int32_t line = RFindLine(aName, &nth, aFromIndex, aImplicitLines);
     *aNth = -nth;
     return line;
@@ -959,17 +960,17 @@ class MOZ_STACK_CLASS nsGridContainerFra
    * on aSide.  For example, for aName "a" and aSide being an end side, it
    * returns the line numbers which would match "a-end" in the relevant axis.
    * For subgrids it includes searching the relevant axis in all ancestor
    * grids too (within this subgrid's spanned area).  If an ancestor has
    * opposite direction, we switch aSide to the opposite logical side so we
    * match on the same physical side as the original subgrid we're resolving
    * the name for.
    */
-  void FindNamedAreas(const nsACString& aName, LogicalSide aSide,
+  void FindNamedAreas(nsAtom* aName, LogicalSide aSide,
                       nsTArray<uint32_t>& aImplicitLines) const {
     // True if we're currently in a map that has the same direction as 'this'.
     bool sameDirectionAsThis = true;
     uint32_t min = !mParentLineNameMap ? 1 : mClampMinLine;
     uint32_t max = mClampMaxLine;
     for (auto* map = this; true;) {
       uint32_t line = map->FindNamedArea(aName, aSide, min, max);
       if (line > 0) {
@@ -1012,20 +1013,20 @@ class MOZ_STACK_CLASS nsGridContainerFra
       map = parent;
     }
   }
 
   /**
    * Return true if any implicit named areas match aName, in this map or
    * in any of our ancestor maps.
    */
-  bool HasImplicitNamedArea(const nsCString& aName) const {
+  bool HasImplicitNamedArea(nsAtom* aName) const {
     const auto* map = this;
     do {
-      if (map->mAreas && map->mAreas->Contains(aName)) {
+      if (map->mAreas && map->mAreas->has(aName)) {
         return true;
       }
       map = map->mParentLineNameMap;
     } while (map);
     return false;
   }
 
   // The min/max line number (1-based) for clamping.
@@ -1034,17 +1035,17 @@ class MOZ_STACK_CLASS nsGridContainerFra
 
  private:
   // Return true if this map represents a subgridded axis.
   bool IsSubgridded() const { return mParentLineNameMap != nullptr; }
 
   /**
    * @see FindNamedLine, this function searches forward.
    */
-  uint32_t FindLine(const nsCString& aName, int32_t* aNth, uint32_t aFromIndex,
+  uint32_t FindLine(nsAtom* aName, int32_t* aNth, uint32_t aFromIndex,
                     const nsTArray<uint32_t>& aImplicitLines) const {
     MOZ_ASSERT(aNth && *aNth > 0);
     int32_t nth = *aNth;
     // For a subgrid we need to search to the end of the grid rather than
     // the end of the local name list, since ancestors might match.
     const uint32_t end = IsSubgridded() ? mClampMaxLine : mTemplateLinesEnd;
     uint32_t line;
     uint32_t i = aFromIndex;
@@ -1069,17 +1070,17 @@ class MOZ_STACK_CLASS nsGridContainerFra
     MOZ_ASSERT(nth > 0, "should have returned a valid line above already");
     *aNth = nth;
     return 0;
   }
 
   /**
    * @see FindNamedLine, this function searches in reverse.
    */
-  uint32_t RFindLine(const nsCString& aName, int32_t* aNth, uint32_t aFromIndex,
+  uint32_t RFindLine(nsAtom* aName, int32_t* aNth, uint32_t aFromIndex,
                      const nsTArray<uint32_t>& aImplicitLines) const {
     MOZ_ASSERT(aNth && *aNth > 0);
     if (MOZ_UNLIKELY(aFromIndex == 0)) {
       return 0;  // There are no named lines beyond the start of the explicit
                  // grid.
     }
     --aFromIndex;  // (shift aFromIndex so we can treat it as inclusive)
     int32_t nth = *aNth;
@@ -1107,17 +1108,17 @@ class MOZ_STACK_CLASS nsGridContainerFra
       }
     }
     MOZ_ASSERT(nth > 0, "should have returned a valid line above already");
     *aNth = nth;
     return 0;
   }
 
   // Return true if aName exists at aIndex in this map or any parent map.
-  bool Contains(uint32_t aIndex, const nsCString& aName) const {
+  bool Contains(uint32_t aIndex, nsAtom* aName) const {
     const auto* map = this;
     while (true) {
       if (aIndex < map->mTemplateLinesEnd && map->HasNameAt(aIndex, aName)) {
         return true;
       }
       auto* parent = map->mParentLineNameMap;
       if (!parent) {
         return false;
@@ -1126,17 +1127,17 @@ class MOZ_STACK_CLASS nsGridContainerFra
       MOZ_ASSERT(line >= 1, "expected a 1-based line number");
       aIndex = line - 1;
       map = parent;
     }
     MOZ_ASSERT_UNREACHABLE("we always return from inside the loop above");
   }
 
   // Return true if aName exists at aIndex in this map.
-  bool HasNameAt(uint32_t aIndex, const nsCString& aName) const {
+  bool HasNameAt(uint32_t aIndex, nsAtom* aName) const {
     if (!mHasRepeatAuto) {
       return mLineNameLists[aIndex].Contains(aName);
     }
     if (aIndex < mRepeatAutoEnd && aIndex >= mRepeatAutoStart &&
         mRepeatAutoLineNameListBefore.Contains(aName)) {
       return true;
     }
     if (aIndex <= mRepeatAutoEnd && aIndex > mRepeatAutoStart &&
@@ -1162,18 +1163,18 @@ class MOZ_STACK_CLASS nsGridContainerFra
   }
 
   /**
    * Return the 1-based line that match aName in 'grid-template-areas'
    * on the side aSide.  Clamp the result to aMin..aMax but require
    * that some part of the area is inside for it to match.
    * Return zero if there is no match.
    */
-  uint32_t FindNamedArea(const nsACString& aName, LogicalSide aSide,
-                         int32_t aMin, int32_t aMax) const {
+  uint32_t FindNamedArea(nsAtom* aName, LogicalSide aSide, int32_t aMin,
+                         int32_t aMax) const {
     if (const NamedArea* area = FindNamedArea(aName)) {
       int32_t start = IsBlock(aSide) ? area->rows.start : area->columns.start;
       int32_t end = IsBlock(aSide) ? area->rows.end : area->columns.end;
       if (IsStart(aSide)) {
         if (start >= aMin) {
           if (start <= aMax) {
             return start;
           }
@@ -1192,35 +1193,35 @@ class MOZ_STACK_CLASS nsGridContainerFra
     }
     return 0;  // no match
   }
 
   /**
    * A convenience method to lookup a name in 'grid-template-areas'.
    * @return null if not found
    */
-  const NamedArea* FindNamedArea(const nsACString& aName) const {
+  const NamedArea* FindNamedArea(nsAtom* aName) const {
     if (mStylePosition->mGridTemplateAreas.IsNone()) {
       return nullptr;
     }
     const auto areas = mStylePosition->mGridTemplateAreas.AsAreas();
     for (const NamedArea& area : areas->areas.AsSpan()) {
-      if (area.name.AsString() == aName) {
+      if (area.name.AsAtom() == aName) {
         return &area;
       }
     }
     return nullptr;
   }
 
   // Some style data references, for easy access.
   const nsStylePosition* mStylePosition;
   const ImplicitNamedAreas* mAreas;
-  const nsTArray<nsTArray<nsCString>>& mLineNameLists;
-  const nsTArray<nsCString>& mRepeatAutoLineNameListBefore;
-  const nsTArray<nsCString>& mRepeatAutoLineNameListAfter;
+  const nsTArray<nsTArray<RefPtr<nsAtom>>>& mLineNameLists;
+  const nsTArray<RefPtr<nsAtom>>& mRepeatAutoLineNameListBefore;
+  const nsTArray<RefPtr<nsAtom>>& mRepeatAutoLineNameListAfter;
   // The index of the repeat(auto-fill/fit) track, or zero if there is none.
   const uint32_t mRepeatAutoStart;
   // The (hypothetical) index of the last such repeat() track.
   const uint32_t mRepeatAutoEnd;
   // The difference between mTemplateLinesEnd and mLineNameLists.Length().
   const int32_t mRepeatEndDelta;
   // The end of the line name lists with repeat(auto-fill/fit) tracks accounted
   // for.  It is equal to mLineNameLists.Length() when a repeat() track
@@ -2098,23 +2099,23 @@ struct nsGridContainerFrame::Tracks {
   nscoord ResolveSize(const LineRange& aRange) const {
     MOZ_ASSERT(mCanResolveLineRangeSize);
     MOZ_ASSERT(aRange.Extent() > 0, "grid items cover at least one track");
     nscoord pos, size;
     aRange.ToPositionAndLength(mSizes, &pos, &size);
     return size;
   }
 
-  nsTArray<nsCString> GetExplicitLineNamesAtIndex(
+  nsTArray<RefPtr<nsAtom>> GetExplicitLineNamesAtIndex(
       const nsStyleGridTemplate& aGridTemplate,
       const TrackSizingFunctions& aFunctions, uint32_t aIndex) {
-    nsTArray<nsCString> lineNames;
+    nsTArray<RefPtr<nsAtom>> lineNames;
 
     bool hasRepeatAuto = aGridTemplate.HasRepeatAuto();
-    const nsTArray<nsTArray<nsCString>>& lineNameLists =
+    const nsTArray<nsTArray<RefPtr<nsAtom>>>& lineNameLists =
         aGridTemplate.mLineNameLists;
 
     if (!hasRepeatAuto) {
       if (aIndex < lineNameLists.Length()) {
         lineNames.AppendElements(lineNameLists[aIndex]);
       }
     } else {
       const uint32_t repeatTrackCount = aFunctions.NumRepeatTracks();
@@ -2705,38 +2706,37 @@ struct MOZ_STACK_CLASS nsGridContainerFr
    * be 'auto'.
    * @param aChild the grid item
    * @param aStyle the StylePosition() for the grid container
    */
   GridArea PlaceDefinite(nsIFrame* aChild, const LineNameMap& aColLineNameMap,
                          const LineNameMap& aRowLineNameMap,
                          const nsStylePosition* aStyle);
 
-  bool HasImplicitNamedArea(const nsCString& aName) const {
-    return mAreas && mAreas->Contains(aName);
+  bool HasImplicitNamedArea(nsAtom* aName) const {
+    return mAreas && mAreas->has(aName);
   }
 
   // Return true if aString ends in aSuffix and has at least one character
   // before the suffix. Assign aIndex to where the suffix starts.
-  static bool IsNameWithSuffix(const nsCString& aString,
-                               const nsCString& aSuffix,
+  static bool IsNameWithSuffix(nsAtom* aString, const nsString& aSuffix,
                                uint32_t* aIndex) {
-    if (StringEndsWith(aString, aSuffix)) {
-      *aIndex = aString.Length() - aSuffix.Length();
+    if (StringEndsWith(nsDependentAtomString(aString), aSuffix)) {
+      *aIndex = aString->GetLength() - aSuffix.Length();
       return *aIndex != 0;
     }
     return false;
   }
 
-  static bool IsNameWithEndSuffix(const nsCString& aString, uint32_t* aIndex) {
-    return IsNameWithSuffix(aString, NS_LITERAL_CSTRING("-end"), aIndex);
-  }
-
-  static bool IsNameWithStartSuffix(const nsCString& aString, uint32_t* aIndex) {
-    return IsNameWithSuffix(aString, NS_LITERAL_CSTRING("-start"), aIndex);
+  static bool IsNameWithEndSuffix(nsAtom* aString, uint32_t* aIndex) {
+    return IsNameWithSuffix(aString, NS_LITERAL_STRING("-end"), aIndex);
+  }
+
+  static bool IsNameWithStartSuffix(nsAtom* aString, uint32_t* aIndex) {
+    return IsNameWithSuffix(aString, NS_LITERAL_STRING("-start"), aIndex);
   }
 
   // Return the relevant parent LineNameMap for the given subgrid axis aAxis.
   const LineNameMap* ParentLineMapForAxis(bool aIsOrthogonal,
                                           LogicalAxis aAxis) const {
     if (!mParentGrid) {
       return nullptr;
     }
@@ -3323,111 +3323,112 @@ nsContainerFrame* NS_NewGridContainerFra
   nsRect* cb = aChild->GetProperty(GridItemContainingBlockRect());
   MOZ_ASSERT(cb,
              "this method must only be called on grid items, and the grid "
              "container should've reflowed this item by now and set up cb");
   return *cb;
 }
 
 void nsGridContainerFrame::AddImplicitNamedAreas(
-    const nsTArray<nsTArray<nsCString>>& aLineNameLists) {
+    const nsTArray<nsTArray<RefPtr<nsAtom>>>& aLineNameLists) {
   // http://dev.w3.org/csswg/css-grid/#implicit-named-areas
   // Note: recording these names for fast lookup later is just an optimization.
   const uint32_t len =
       std::min(aLineNameLists.Length(), size_t(nsStyleGridLine::kMaxLine));
   nsTHashtable<nsStringHashKey> currentStarts;
   ImplicitNamedAreas* areas = GetImplicitNamedAreas();
   for (uint32_t i = 0; i < len; ++i) {
-    for (const nsCString& name : aLineNameLists[i]) {
+    for (nsAtom* name : aLineNameLists[i]) {
       uint32_t indexOfSuffix;
       if (Grid::IsNameWithStartSuffix(name, &indexOfSuffix) ||
           Grid::IsNameWithEndSuffix(name, &indexOfSuffix)) {
         // Extract the name that was found earlier.
-        nsDependentCSubstring areaName(name, 0, indexOfSuffix);
+        nsDependentSubstring areaName(nsDependentAtomString(name), 0,
+                                      indexOfSuffix);
 
         // Lazily create the ImplicitNamedAreas.
         if (!areas) {
           areas = new ImplicitNamedAreas;
           SetProperty(ImplicitNamedAreasProperty(), areas);
         }
 
-        NamedArea area;
-        if (!areas->Get(areaName, &area)) {
-          // Not found, so prep the newly-seen area with a name and empty
-          // boundary information, which will get filled in later.
-          Servo_MakeOwnedStr(&area.name, &areaName);
-          area.rows = {0, 0};
-          area.columns = {0, 0};
-
-          areas->Put(areaName, area);
+        RefPtr<nsAtom> name = NS_Atomize(areaName);
+        auto addPtr = areas->lookupForAdd(name);
+        if (!addPtr) {
+          if (!areas->add(
+                  addPtr, name,
+                  NamedArea{StyleAtom(do_AddRef(name)), {0, 0}, {0, 0}})) {
+            MOZ_CRASH("OOM while adding grid name lists");
+          }
         }
       }
     }
   }
 }
 
 void nsGridContainerFrame::InitImplicitNamedAreas(
     const nsStylePosition* aStyle) {
   ImplicitNamedAreas* areas = GetImplicitNamedAreas();
   if (areas) {
     // Clear it, but reuse the hashtable itself for now.  We'll remove it
     // below if it isn't needed anymore.
-    areas->Clear();
+    areas->clear();
   }
   AddImplicitNamedAreas(aStyle->GridTemplateColumns().mLineNameLists);
   AddImplicitNamedAreas(aStyle->GridTemplateRows().mLineNameLists);
-  if (areas && areas->Count() == 0) {
+  if (areas && areas->count() == 0) {
     DeleteProperty(ImplicitNamedAreasProperty());
   }
 }
 
 int32_t nsGridContainerFrame::Grid::ResolveLine(
     const nsStyleGridLine& aLine, int32_t aNth, uint32_t aFromIndex,
     const LineNameMap& aNameMap, LogicalSide aSide, uint32_t aExplicitGridEnd,
     const nsStylePosition* aStyle) {
   MOZ_ASSERT(!aLine.IsAuto());
   int32_t line = 0;
-  if (aLine.mLineName.IsEmpty()) {
+  if (aLine.mLineName == nsGkAtoms::_empty) {
     MOZ_ASSERT(aNth != 0, "css-grid 9.2: <integer> must not be zero.");
     line = int32_t(aFromIndex) + aNth;
   } else {
     if (aNth == 0) {
       // <integer> was omitted; treat it as 1.
       aNth = 1;
     }
     bool isNameOnly = !aLine.mHasSpan && aLine.mInteger == 0;
     if (isNameOnly) {
       AutoTArray<uint32_t, 16> implicitLines;
       aNameMap.FindNamedAreas(aLine.mLineName, aSide, implicitLines);
       if (!implicitLines.IsEmpty() ||
           aNameMap.HasImplicitNamedArea(aLine.mLineName)) {
         // aName is a named area - look for explicit lines named
         // <name>-start/-end depending on which side we're resolving.
         // http://dev.w3.org/csswg/css-grid/#grid-placement-slot
-        nsAutoCString lineName(aLine.mLineName);
+        nsAutoString lineName(nsDependentAtomString(aLine.mLineName));
         if (IsStart(aSide)) {
           lineName.AppendLiteral("-start");
         } else {
           lineName.AppendLiteral("-end");
         }
-        line =
-            aNameMap.FindNamedLine(lineName, &aNth, aFromIndex, implicitLines);
+        RefPtr<nsAtom> name = NS_Atomize(lineName);
+        line = aNameMap.FindNamedLine(name, &aNth, aFromIndex, implicitLines);
       }
     }
 
     if (line == 0) {
       // If mLineName ends in -start/-end, try the prefix as a named area.
       AutoTArray<uint32_t, 16> implicitLines;
       uint32_t index;
       bool useStart = IsNameWithStartSuffix(aLine.mLineName, &index);
       if (useStart || IsNameWithEndSuffix(aLine.mLineName, &index)) {
         auto side = MakeLogicalSide(
             GetAxis(aSide), useStart ? eLogicalEdgeStart : eLogicalEdgeEnd);
-        aNameMap.FindNamedAreas(nsDependentCSubstring(aLine.mLineName, 0, index),
-                                side, implicitLines);
+        RefPtr<nsAtom> name = NS_Atomize(nsDependentSubstring(
+            nsDependentAtomString(aLine.mLineName), 0, index));
+        aNameMap.FindNamedAreas(name, side, implicitLines);
       }
       line = aNameMap.FindNamedLine(aLine.mLineName, &aNth, aFromIndex,
                                     implicitLines);
     }
 
     if (line == 0) {
       MOZ_ASSERT(aNth != 0, "we found all N named lines but 'line' is zero!");
       int32_t edgeLine;
@@ -3454,17 +3455,17 @@ nsGridContainerFrame::Grid::ResolveLineR
     const LineNameMap& aNameMap, LogicalAxis aAxis, uint32_t aExplicitGridEnd,
     const nsStylePosition* aStyle) {
   MOZ_ASSERT(int32_t(nsGridContainerFrame::kAutoLine) >
              nsStyleGridLine::kMaxLine);
 
   if (aStart.mHasSpan) {
     if (aEnd.mHasSpan || aEnd.IsAuto()) {
       // http://dev.w3.org/csswg/css-grid/#grid-placement-errors
-      if (aStart.mLineName.IsEmpty()) {
+      if (aStart.mLineName == nsGkAtoms::_empty) {
         // span <integer> / span *
         // span <integer> / auto
         return LinePair(kAutoLine, aStart.mInteger);
       }
       // span <custom-ident> / span *
       // span <custom-ident> / auto
       return LinePair(kAutoLine, 1);  // XXX subgrid explicit size instead of 1?
     }
@@ -3488,17 +3489,17 @@ nsGridContainerFrame::Grid::ResolveLineR
 
   int32_t start = kAutoLine;
   if (aStart.IsAuto()) {
     if (aEnd.IsAuto()) {
       // auto / auto
       return LinePair(start, 1);  // XXX subgrid explicit size instead of 1?
     }
     if (aEnd.mHasSpan) {
-      if (aEnd.mLineName.IsEmpty()) {
+      if (aEnd.mLineName == nsGkAtoms::_empty) {
         // auto / span <integer>
         MOZ_ASSERT(aEnd.mInteger != 0);
         return LinePair(start, aEnd.mInteger);
       }
       // http://dev.w3.org/csswg/css-grid/#grid-placement-errors
       // auto / span <custom-ident>
       return LinePair(start, 1);  // XXX subgrid explicit size instead of 1?
     }
@@ -3514,17 +3515,17 @@ nsGridContainerFrame::Grid::ResolveLineR
       return LinePair(start, start);
     }
   }
 
   uint32_t from;
   int32_t nth = aEnd.mInteger == 0 ? 1 : aEnd.mInteger;
   if (aEnd.mHasSpan) {
     if (MOZ_UNLIKELY(start < 0)) {
-      if (aEnd.mLineName.IsEmpty()) {
+      if (aEnd.mLineName == nsGkAtoms::_empty) {
         return LinePair(start, start + nth);
       }
       from = 0;
     } else {
       if (start >= int32_t(aExplicitGridEnd)) {
         // The start is at or after the last explicit line, thus all lines
         // after it match <custom-ident> since they're implicit.
         return LinePair(start, std::min(start + nth, aNameMap.mClampMaxLine));
@@ -4286,24 +4287,24 @@ void nsGridContainerFrame::Grid::PlaceGr
     aState.mColFunctions.SetNumRepeatTracks(colRepeatCount - numEmptyCols);
     auto rowRepeatCount = aState.mRowFunctions.NumRepeatTracks();
     aState.mRowFunctions.SetNumRepeatTracks(rowRepeatCount - numEmptyRows);
   }
 
   // Update the line boundaries of the implicit grid areas, if needed.
   if (mAreas &&
       aState.mFrame->HasAnyStateBits(NS_STATE_GRID_GENERATE_COMPUTED_VALUES)) {
-    for (auto iter = mAreas->Iter(); !iter.Done(); iter.Next()) {
-      auto& areaInfo = iter.Data();
+    for (auto iter = mAreas->iter(); !iter.done(); iter.next()) {
+      auto& areaInfo = iter.get().value();
 
       // Resolve the lines for the area. We use the name of the area as the
       // name of the lines, knowing that the line placement algorithm will
       // add the -start and -end suffixes as appropriate for layout.
       nsStyleGridLine lineStartAndEnd;
-      lineStartAndEnd.mLineName = areaInfo.name.AsString();
+      lineStartAndEnd.mLineName = areaInfo.name.AsAtom();
 
       LineRange columnLines =
           ResolveLineRange(lineStartAndEnd, lineStartAndEnd, colLineNameMap,
                            eLogicalAxisInline, mExplicitGridColEnd, gridStyle);
 
       LineRange rowLines =
           ResolveLineRange(lineStartAndEnd, lineStartAndEnd, rowLineNameMap,
                            eLogicalAxisBlock, mExplicitGridRowEnd, gridStyle);
@@ -7278,19 +7279,19 @@ void nsGridContainerFrame::Reflow(nsPres
           ((row >= gridReflowInput.mRowFunctions.mRepeatAutoStart) &&
            (row < gridReflowInput.mRowFunctions.mRepeatAutoEnd));
       rowTrackStates.AppendElement(
           isRepeat ? (uint32_t)mozilla::dom::GridTrackState::Repeat
                    : (uint32_t)mozilla::dom::GridTrackState::Static);
 
       row++;
     }
-    // Row info has to accomodate fragmentation of the grid, which may happen in
-    // later calls to Reflow. For now, presume that no more fragmentation will
-    // occur.
+    // Row info has to accommodate fragmentation of the grid, which may happen
+    // in later calls to Reflow. For now, presume that no more fragmentation
+    // will occur.
     ComputedGridTrackInfo* rowInfo = new ComputedGridTrackInfo(
         gridReflowInput.mRowFunctions.mExplicitGridOffset,
         IsSubgrid(eLogicalAxisBlock)
             ? rowTrackSizes.Length()
             : gridReflowInput.mRowFunctions.NumExplicitTracks(),
         gridReflowInput.mStartRow, row, std::move(rowTrackPositions),
         std::move(rowTrackSizes), std::move(rowTrackStates),
         std::move(rowRemovedRepeatTracks),
@@ -7330,28 +7331,28 @@ void nsGridContainerFrame::Reflow(nsPres
     // repeat tracks produced in the reflow. Only explicit names are assigned
     // to lines here; the mozilla::dom::GridLines class will later extract
     // implicit names from grid areas and assign them to the appropriate lines.
 
     // Generate column lines first.
     uint32_t capacity = gridReflowInput.mCols.mSizes.Length();
     const nsStyleGridTemplate& gridColTemplate =
         gridReflowInput.mGridStyle->GridTemplateColumns();
-    nsTArray<nsTArray<nsCString>> columnLineNames(capacity);
+    nsTArray<nsTArray<RefPtr<nsAtom>>> columnLineNames(capacity);
     for (col = 0; col <= gridReflowInput.mCols.mSizes.Length(); col++) {
       // Offset col by the explicit grid offset, to get the original names.
-      nsTArray<nsCString> explicitNames =
+      nsTArray<RefPtr<nsAtom>> explicitNames =
           gridReflowInput.mCols.GetExplicitLineNamesAtIndex(
               gridColTemplate, gridReflowInput.mColFunctions,
               col - gridReflowInput.mColFunctions.mExplicitGridOffset);
 
       columnLineNames.AppendElement(explicitNames);
     }
     // Get the explicit names that follow a repeat auto declaration.
-    nsTArray<nsCString> colNamesFollowingRepeat;
+    nsTArray<RefPtr<nsAtom>> colNamesFollowingRepeat;
     if (gridColTemplate.HasRepeatAuto()) {
       // The line name list after the repeatAutoIndex holds the line names
       // for the first explicit line after the repeat auto declaration.
       uint32_t repeatAutoEnd = gridColTemplate.mRepeatAutoIndex + 1;
       MOZ_ASSERT(repeatAutoEnd < gridColTemplate.mLineNameLists.Length());
       colNamesFollowingRepeat.AppendElements(
           gridColTemplate.mLineNameLists[repeatAutoEnd]);
     }
@@ -7362,28 +7363,28 @@ void nsGridContainerFrame::Reflow(nsPres
                                  gridColTemplate.mRepeatAutoLineNameListAfter,
                                  std::move(colNamesFollowingRepeat));
     SetProperty(GridColumnLineInfo(), columnLineInfo);
 
     // Generate row lines next.
     capacity = gridReflowInput.mRows.mSizes.Length();
     const nsStyleGridTemplate& gridRowTemplate =
         gridReflowInput.mGridStyle->GridTemplateRows();
-    nsTArray<nsTArray<nsCString>> rowLineNames(capacity);
+    nsTArray<nsTArray<RefPtr<nsAtom>>> rowLineNames(capacity);
     for (row = 0; row <= gridReflowInput.mRows.mSizes.Length(); row++) {
       // Offset row by the explicit grid offset, to get the original names.
-      nsTArray<nsCString> explicitNames =
+      nsTArray<RefPtr<nsAtom>> explicitNames =
           gridReflowInput.mRows.GetExplicitLineNamesAtIndex(
               gridRowTemplate, gridReflowInput.mRowFunctions,
               row - gridReflowInput.mRowFunctions.mExplicitGridOffset);
 
       rowLineNames.AppendElement(explicitNames);
     }
     // Get the explicit names that follow a repeat auto declaration.
-    nsTArray<nsCString> rowNamesFollowingRepeat;
+    nsTArray<RefPtr<nsAtom>> rowNamesFollowingRepeat;
     if (gridRowTemplate.HasRepeatAuto()) {
       // The line name list after the repeatAutoIndex holds the line names
       // for the first explicit line after the repeat auto declaration.
       uint32_t repeatAutoEnd = gridRowTemplate.mRepeatAutoIndex + 1;
       MOZ_ASSERT(repeatAutoEnd < gridRowTemplate.mLineNameLists.Length());
       rowNamesFollowingRepeat.AppendElements(
           gridRowTemplate.mLineNameLists[repeatAutoEnd]);
     }
--- a/layout/generic/nsGridContainerFrame.h
+++ b/layout/generic/nsGridContainerFrame.h
@@ -6,19 +6,18 @@
 
 /* rendering object for CSS "display: grid | inline-grid" */
 
 #ifndef nsGridContainerFrame_h___
 #define nsGridContainerFrame_h___
 
 #include "mozilla/Maybe.h"
 #include "mozilla/TypeTraits.h"
+#include "mozilla/HashTable.h"
 #include "nsContainerFrame.h"
-#include "nsHashKeys.h"
-#include "nsTHashtable.h"
 
 namespace mozilla {
 class PresShell;
 }  // namespace mozilla
 
 /**
  * Factory function.
  * @return a newly allocated nsGridContainerFrame (infallible)
@@ -62,28 +61,29 @@ struct ComputedGridTrackInfo {
   nsTArray<nscoord> mPositions;
   nsTArray<nscoord> mSizes;
   nsTArray<uint32_t> mStates;
   nsTArray<bool> mRemovedRepeatTracks;
   uint32_t mRepeatFirstTrack;
 };
 
 struct ComputedGridLineInfo {
-  explicit ComputedGridLineInfo(nsTArray<nsTArray<nsCString>>&& aNames,
-                                const nsTArray<nsCString>& aNamesBefore,
-                                const nsTArray<nsCString>& aNamesAfter,
-                                nsTArray<nsCString>&& aNamesFollowingRepeat)
+  explicit ComputedGridLineInfo(
+      nsTArray<nsTArray<RefPtr<nsAtom>>>&& aNames,
+      const nsTArray<RefPtr<nsAtom>>& aNamesBefore,
+      const nsTArray<RefPtr<nsAtom>>& aNamesAfter,
+      nsTArray<RefPtr<nsAtom>>&& aNamesFollowingRepeat)
       : mNames(aNames),
         mNamesBefore(aNamesBefore),
         mNamesAfter(aNamesAfter),
         mNamesFollowingRepeat(aNamesFollowingRepeat) {}
-  nsTArray<nsTArray<nsCString>> mNames;
-  nsTArray<nsCString> mNamesBefore;
-  nsTArray<nsCString> mNamesAfter;
-  nsTArray<nsCString> mNamesFollowingRepeat;
+  nsTArray<nsTArray<RefPtr<nsAtom>>> mNames;
+  nsTArray<RefPtr<nsAtom>> mNamesBefore;
+  nsTArray<RefPtr<nsAtom>> mNamesAfter;
+  nsTArray<RefPtr<nsAtom>> mNamesFollowingRepeat;
 };
 }  // namespace mozilla
 
 class nsGridContainerFrame final : public nsContainerFrame {
  public:
   NS_DECL_FRAMEARENA_HELPERS(nsGridContainerFrame)
   NS_DECL_QUERYFRAME
   using ComputedGridTrackInfo = mozilla::ComputedGridTrackInfo;
@@ -197,17 +197,31 @@ class nsGridContainerFrame final : publi
 
   NS_DECLARE_FRAME_PROPERTY_DELETABLE(GridRowLineInfo, ComputedGridLineInfo)
   const ComputedGridLineInfo* GetComputedTemplateRowLines() {
     const ComputedGridLineInfo* info = GetProperty(GridRowLineInfo());
     MOZ_ASSERT(info, "Property generation wasn't requested.");
     return info;
   }
 
-  using ImplicitNamedAreas = nsBaseHashtable<nsCStringHashKey, NamedArea, NamedArea>;
+  struct AtomKey {
+    RefPtr<nsAtom> mKey;
+
+    explicit AtomKey(nsAtom* aAtom) : mKey(aAtom) {}
+
+    using Lookup = nsAtom*;
+
+    static mozilla::HashNumber hash(const Lookup& aKey) { return aKey->hash(); }
+
+    static bool match(const AtomKey& aFirst, const Lookup& aSecond) {
+      return aFirst.mKey == aSecond;
+    }
+  };
+
+  using ImplicitNamedAreas = mozilla::HashMap<AtomKey, NamedArea, AtomKey>;
   NS_DECLARE_FRAME_PROPERTY_DELETABLE(ImplicitNamedAreasProperty,
                                       ImplicitNamedAreas)
   ImplicitNamedAreas* GetImplicitNamedAreas() const {
     return GetProperty(ImplicitNamedAreasProperty());
   }
 
   using ExplicitNamedAreas = mozilla::StyleOwnedSlice<NamedArea>;
   NS_DECLARE_FRAME_PROPERTY_DELETABLE(ExplicitNamedAreasProperty,
@@ -310,17 +324,17 @@ class nsGridContainerFrame final : publi
   /**
    * XXX temporary - move the ImplicitNamedAreas stuff to the style system.
    * The implicit area names that come from x-start .. x-end lines in
    * grid-template-columns / grid-template-rows are stored in this frame
    * property when needed, as a ImplicitNamedAreas* value.
    */
   void InitImplicitNamedAreas(const nsStylePosition* aStyle);
   void AddImplicitNamedAreas(
-      const nsTArray<nsTArray<nsCString>>& aLineNameLists);
+      const nsTArray<nsTArray<RefPtr<nsAtom>>>& aLineNameLists);
 
   void NormalizeChildLists();
 
   /**
    * Reflow and place our children.
    * @return the consumed size of all of this grid container's continuations
    *         so far including this frame
    */
--- a/layout/style/GeckoBindings.cpp
+++ b/layout/style/GeckoBindings.cpp
@@ -1253,18 +1253,17 @@ void Gecko_ClearPODTArray(void* aArray, 
       0, base->Length(), 0, aElementSize, aElementAlign);
 }
 
 void Gecko_ResizeTArrayForStrings(nsTArray<nsString>* aArray,
                                   uint32_t aLength) {
   aArray->SetLength(aLength);
 }
 
-void Gecko_ResizeTArrayForCStrings(nsTArray<nsCString>* aArray,
-                                  uint32_t aLength) {
+void Gecko_ResizeAtomArray(nsTArray<RefPtr<nsAtom>>* aArray, uint32_t aLength) {
   aArray->SetLength(aLength);
 }
 
 void Gecko_SetStyleGridTemplate(UniquePtr<nsStyleGridTemplate>* aGridTemplate,
                                 nsStyleGridTemplate* aValue) {
   aGridTemplate->reset(aValue);
 }
 
--- a/layout/style/GeckoBindings.h
+++ b/layout/style/GeckoBindings.h
@@ -411,17 +411,17 @@ void Gecko_EnsureTArrayCapacity(void* ar
 
 // Same here, `array` must be an nsTArray<T>, for some T.
 //
 // Important note: Only valid for POD types, since destructors won't be run
 // otherwise. This is ensured with rust traits for the relevant structs.
 void Gecko_ClearPODTArray(void* array, size_t elem_size, size_t elem_align);
 
 void Gecko_ResizeTArrayForStrings(nsTArray<nsString>* array, uint32_t length);
-void Gecko_ResizeTArrayForCStrings(nsTArray<nsCString>* array, uint32_t length);
+void Gecko_ResizeAtomArray(nsTArray<RefPtr<nsAtom>>* array, uint32_t length);
 
 void Gecko_SetStyleGridTemplate(
     mozilla::UniquePtr<nsStyleGridTemplate>* grid_template,
     nsStyleGridTemplate* value);
 
 nsStyleGridTemplate* Gecko_CreateStyleGridTemplate(uint32_t track_sizes,
                                                    uint32_t name_size);
 
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -1240,49 +1240,49 @@ void nsComputedDOMStyle::SetValueToURLVa
   nsAutoString url;
   url.AppendLiteral(u"url(");
   nsStyleUtil::AppendEscapedCSSString(source, url, '"');
   url.Append(')');
   aValue->SetString(url);
 }
 
 void nsComputedDOMStyle::AppendGridLineNames(
-    nsString& aResult, const nsTArray<nsCString>& aLineNames) {
+    nsString& aResult, const nsTArray<RefPtr<nsAtom>>& aLineNames) {
   uint32_t numLines = aLineNames.Length();
   if (numLines == 0) {
     return;
   }
   for (uint32_t i = 0;;) {
-    nsStyleUtil::AppendEscapedCSSIdent(NS_ConvertUTF8toUTF16(aLineNames[i]),
+    nsStyleUtil::AppendEscapedCSSIdent(nsDependentAtomString(aLineNames[i]),
                                        aResult);
     if (++i == numLines) {
       break;
     }
     aResult.Append(' ');
   }
 }
 
 void nsComputedDOMStyle::AppendGridLineNames(
-    nsDOMCSSValueList* aValueList, const nsTArray<nsCString>& aLineNames,
+    nsDOMCSSValueList* aValueList, const nsTArray<RefPtr<nsAtom>>& aLineNames,
     bool aSuppressEmptyList) {
   if (aLineNames.IsEmpty() && aSuppressEmptyList) {
     return;
   }
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   nsAutoString lineNamesString;
   lineNamesString.Assign('[');
   AppendGridLineNames(lineNamesString, aLineNames);
   lineNamesString.Append(']');
   val->SetString(lineNamesString);
   aValueList->AppendCSSValue(val.forget());
 }
 
 void nsComputedDOMStyle::AppendGridLineNames(
-    nsDOMCSSValueList* aValueList, const nsTArray<nsCString>& aLineNames1,
-    const nsTArray<nsCString>& aLineNames2) {
+    nsDOMCSSValueList* aValueList, const nsTArray<RefPtr<nsAtom>>& aLineNames1,
+    const nsTArray<RefPtr<nsAtom>>& aLineNames2) {
   if (aLineNames1.IsEmpty() && aLineNames2.IsEmpty()) {
     return;
   }
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   nsAutoString lineNamesString;
   lineNamesString.Assign('[');
   if (!aLineNames1.IsEmpty()) {
     AppendGridLineNames(lineNamesString, aLineNames1);
@@ -1477,17 +1477,18 @@ already_AddRefed<CSSValue> nsComputedDOM
           repeatIndex++;
         }
         repeatIndex++;
       };
 
       for (int32_t i = 0;; i++) {
         if (aTrackList.HasRepeatAuto()) {
           if (i == aTrackList.mRepeatAutoIndex) {
-            const nsTArray<nsCString>& lineNames = aTrackList.mLineNameLists[i];
+            const nsTArray<RefPtr<nsAtom>>& lineNames =
+                aTrackList.mLineNameLists[i];
             if (i == endOfRepeat) {
               // All auto-fit tracks are empty, but we report them anyway.
               AppendGridLineNames(valueList, lineNames,
                                   aTrackList.mRepeatAutoLineNameListBefore);
 
               AppendRemovedAutoFits(LinesBetween);
 
               AppendGridLineNames(valueList,
@@ -1497,32 +1498,34 @@ already_AddRefed<CSSValue> nsComputedDOM
               AppendGridLineNames(valueList, lineNames,
                                   aTrackList.mRepeatAutoLineNameListBefore);
               AppendRemovedAutoFits(LinesFollow);
             }
           } else if (i == endOfRepeat) {
             // Before appending the last line, finish off any removed auto-fits.
             AppendRemovedAutoFits(LinesPrecede);
 
-            const nsTArray<nsCString>& lineNames =
+            const nsTArray<RefPtr<nsAtom>>& lineNames =
                 aTrackList.mLineNameLists[aTrackList.mRepeatAutoIndex + 1];
             AppendGridLineNames(
                 valueList, aTrackList.mRepeatAutoLineNameListAfter, lineNames);
           } else if (i > aTrackList.mRepeatAutoIndex && i < endOfRepeat) {
             AppendGridLineNames(valueList,
                                 aTrackList.mRepeatAutoLineNameListAfter,
                                 aTrackList.mRepeatAutoLineNameListBefore);
             AppendRemovedAutoFits(LinesFollow);
           } else {
             uint32_t j = i > endOfRepeat ? i - offsetToLastRepeat : i;
-            const nsTArray<nsCString>& lineNames = aTrackList.mLineNameLists[j];
+            const nsTArray<RefPtr<nsAtom>>& lineNames =
+                aTrackList.mLineNameLists[j];
             AppendGridLineNames(valueList, lineNames);
           }
         } else {
-          const nsTArray<nsCString>& lineNames = aTrackList.mLineNameLists[i];
+          const nsTArray<RefPtr<nsAtom>>& lineNames =
+              aTrackList.mLineNameLists[i];
           AppendGridLineNames(valueList, lineNames);
         }
         if (uint32_t(i) == numExplicitTracks) {
           break;
         }
         RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
         val->SetAppUnits(trackSizes[i + numLeadingImplicitTracks]);
         valueList->AppendCSSValue(val.forget());
@@ -1535,17 +1538,17 @@ already_AddRefed<CSSValue> nsComputedDOM
       RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
       val->SetAppUnits(trackSizes[i]);
       valueList->AppendCSSValue(val.forget());
     }
   } else {
     // We don't have a frame.  So, we'll just return a serialization of
     // the tracks from the style (without resolved sizes).
     for (uint32_t i = 0;; i++) {
-      const nsTArray<nsCString>& lineNames = aTrackList.mLineNameLists[i];
+      const nsTArray<RefPtr<nsAtom>>& lineNames = aTrackList.mLineNameLists[i];
       if (!lineNames.IsEmpty()) {
         AppendGridLineNames(valueList, lineNames);
       }
       if (i == numSizes) {
         break;
       }
       if (MOZ_UNLIKELY(aTrackList.IsRepeatAutoIndex(i))) {
         RefPtr<nsROCSSPrimitiveValue> start = new nsROCSSPrimitiveValue;
@@ -1633,21 +1636,21 @@ already_AddRefed<CSSValue> nsComputedDOM
   }
 
   if (aGridLine.mInteger != 0) {
     RefPtr<nsROCSSPrimitiveValue> integer = new nsROCSSPrimitiveValue;
     integer->SetNumber(aGridLine.mInteger);
     valueList->AppendCSSValue(integer.forget());
   }
 
-  if (!aGridLine.mLineName.IsEmpty()) {
+  if (aGridLine.mLineName != nsGkAtoms::_empty) {
     RefPtr<nsROCSSPrimitiveValue> lineName = new nsROCSSPrimitiveValue;
     nsString escapedLineName;
     nsStyleUtil::AppendEscapedCSSIdent(
-        NS_ConvertUTF8toUTF16(aGridLine.mLineName), escapedLineName);
+        nsDependentAtomString(aGridLine.mLineName), escapedLineName);
     lineName->SetString(escapedLineName);
     valueList->AppendCSSValue(lineName.forget());
   }
 
   NS_ASSERTION(valueList->Length() > 0,
                "Should have appended at least one value");
   return valueList.forget();
 }
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -186,26 +186,26 @@ class nsComputedDOMStyle final : public 
   already_AddRefed<CSSValue> GetBorderColorFor(mozilla::Side aSide);
 
   already_AddRefed<CSSValue> GetMarginWidthFor(mozilla::Side aSide);
 
   already_AddRefed<CSSValue> GetTransformValue(const mozilla::StyleTransform&);
 
   // Appends all aLineNames (may be empty) space-separated to aResult.
   void AppendGridLineNames(nsString& aResult,
-                           const nsTArray<nsCString>& aLineNames);
+                           const nsTArray<RefPtr<nsAtom>>& aLineNames);
   // Appends aLineNames as a CSSValue* to aValueList.  If aLineNames is empty
   // a value ("[]") is only appended if aSuppressEmptyList is false.
   void AppendGridLineNames(nsDOMCSSValueList* aValueList,
-                           const nsTArray<nsCString>& aLineNames,
+                           const nsTArray<RefPtr<nsAtom>>& aLineNames,
                            bool aSuppressEmptyList = true);
   // Appends aLineNames1/2 (if non-empty) as a CSSValue* to aValueList.
   void AppendGridLineNames(nsDOMCSSValueList* aValueList,
-                           const nsTArray<nsCString>& aLineNames1,
-                           const nsTArray<nsCString>& aLineNames2);
+                           const nsTArray<RefPtr<nsAtom>>& aLineNames1,
+                           const nsTArray<RefPtr<nsAtom>>& aLineNames2);
   already_AddRefed<CSSValue> GetGridTrackSize(const nsStyleCoord& aMinSize,
                                               const nsStyleCoord& aMaxSize);
   already_AddRefed<CSSValue> GetGridTemplateColumnsRows(
       const nsStyleGridTemplate& aTrackList,
       const mozilla::ComputedGridTrackInfo* aTrackInfo);
   already_AddRefed<CSSValue> GetGridLine(const nsStyleGridLine& aGridLine);
 
   bool GetLineHeightCoord(nscoord& aCoord);
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -945,45 +945,42 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
       mMozListReversed;  // true in an <ol reversed> scope
 };
 
 struct nsStyleGridLine {
   // http://dev.w3.org/csswg/css-grid/#typedef-grid-line
   // XXXmats we could optimize memory size here
   bool mHasSpan;
   int32_t mInteger;    // 0 means not provided
-  nsCString mLineName;  // Empty string means not provided.
+  RefPtr<nsAtom> mLineName;  // Empty string means not provided.
 
   // These are the limits that we choose to clamp grid line numbers to.
   // http://dev.w3.org/csswg/css-grid/#overlarge-grids
   // mInteger is clamped to this range:
   static const int32_t kMinLine = -10000;
   static const int32_t kMaxLine = 10000;
 
   nsStyleGridLine()
-      : mHasSpan(false),
-        mInteger(0)
-  // mLineName get its default constructor, the empty string
-  {}
+      : mHasSpan(false), mInteger(0), mLineName(nsGkAtoms::_empty) {}
 
   nsStyleGridLine(const nsStyleGridLine& aOther) { (*this) = aOther; }
 
   void operator=(const nsStyleGridLine& aOther) {
     mHasSpan = aOther.mHasSpan;
     mInteger = aOther.mInteger;
     mLineName = aOther.mLineName;
   }
 
   bool operator!=(const nsStyleGridLine& aOther) const {
     return mHasSpan != aOther.mHasSpan || mInteger != aOther.mInteger ||
            mLineName != aOther.mLineName;
   }
 
   bool IsAuto() const {
-    bool haveInitialValues = mInteger == 0 && mLineName.IsEmpty();
+    bool haveInitialValues = mInteger == 0 && mLineName == nsGkAtoms::_empty;
     MOZ_ASSERT(!(haveInitialValues && mHasSpan),
                "should not have 'span' when other components are "
                "at their initial values");
     return haveInitialValues;
   }
 };
 
 // Computed value of the grid-template-columns or grid-template-rows property
@@ -1022,21 +1019,21 @@ struct nsStyleGridLine {
 // If mRepeatAutoIndex != -1 then that index is an <auto-repeat> and
 // mIsAutoFill == true means it's an 'auto-fill', otherwise 'auto-fit'.
 // mRepeatAutoLineNameListBefore is the list of line names before the track
 // size, mRepeatAutoLineNameListAfter the names after.  (They are empty
 // when there is no <auto-repeat> track, i.e. when mRepeatAutoIndex == -1).
 // When mIsSubgrid is true, mRepeatAutoLineNameListBefore contains the line
 // names and mRepeatAutoLineNameListAfter is empty.
 struct nsStyleGridTemplate {
-  nsTArray<nsTArray<nsCString>> mLineNameLists;
+  nsTArray<nsTArray<RefPtr<nsAtom>>> mLineNameLists;
   nsTArray<nsStyleCoord> mMinTrackSizingFunctions;
   nsTArray<nsStyleCoord> mMaxTrackSizingFunctions;
-  nsTArray<nsCString> mRepeatAutoLineNameListBefore;
-  nsTArray<nsCString> mRepeatAutoLineNameListAfter;
+  nsTArray<RefPtr<nsAtom>> mRepeatAutoLineNameListBefore;
+  nsTArray<RefPtr<nsAtom>> mRepeatAutoLineNameListAfter;
   int16_t mRepeatAutoIndex;  // -1 or the track index for an auto-fill/fit track
   bool mIsAutoFill : 1;
   bool mIsSubgrid : 1;
 
   nsStyleGridTemplate()
       : mRepeatAutoIndex(-1), mIsAutoFill(false), mIsSubgrid(false) {}
 
   inline bool operator==(const nsStyleGridTemplate& aOther) const {
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -1132,52 +1132,55 @@ fn static_assert() {
 
     ${impl_simple_copy('order', 'mOrder')}
 
     % for value in GRID_LINES:
     pub fn set_${value.name}(&mut self, v: longhands::${value.name}::computed_value::T) {
         use crate::gecko_bindings::structs::{nsStyleGridLine_kMinLine, nsStyleGridLine_kMaxLine};
 
         let line = &mut self.gecko.${value.gecko};
-        let line_name = &mut line.mLineName;
-        match v.ident.as_ref() {
-            Some(i) => i.0.with_str(|s| line_name.assign(s)),
-            None => line_name.assign(""),
-        };
+        line.mLineName.set_move(unsafe {
+            RefPtr::from_addrefed(match v.ident {
+                Some(i) => i.0,
+                None => atom!(""),
+            }.into_addrefed())
+        });
         line.mHasSpan = v.is_span;
         if let Some(integer) = v.line_num {
             // clamping the integer between a range
             line.mInteger = cmp::max(
                 nsStyleGridLine_kMinLine,
                 cmp::min(integer, nsStyleGridLine_kMaxLine),
             );
         }
     }
 
     pub fn copy_${value.name}_from(&mut self, other: &Self) {
         self.gecko.${value.gecko}.mHasSpan = other.gecko.${value.gecko}.mHasSpan;
         self.gecko.${value.gecko}.mInteger = other.gecko.${value.gecko}.mInteger;
-        self.gecko.${value.gecko}.mLineName.assign(&*other.gecko.${value.gecko}.mLineName);
+        unsafe {
+            self.gecko.${value.gecko}.mLineName.set(&other.gecko.${value.gecko}.mLineName);
+        }
     }
 
     pub fn reset_${value.name}(&mut self, other: &Self) {
         self.copy_${value.name}_from(other)
     }
 
     pub fn clone_${value.name}(&self) -> longhands::${value.name}::computed_value::T {
         use crate::gecko_bindings::structs::{nsStyleGridLine_kMinLine, nsStyleGridLine_kMaxLine};
 
         longhands::${value.name}::computed_value::T {
             is_span: self.gecko.${value.gecko}.mHasSpan,
             ident: {
-                let name = self.gecko.${value.gecko}.mLineName.to_string();
-                if name.len() == 0 {
+                let name = unsafe { Atom::from_raw(self.gecko.${value.gecko}.mLineName.mRawPtr) };
+                if name == atom!("") {
                     None
                 } else {
-                    Some(CustomIdent(Atom::from(name)))
+                    Some(CustomIdent(name))
                 }
             },
             line_num:
                 if self.gecko.${value.gecko}.mInteger == 0 {
                     None
                 } else {
                     debug_assert!(nsStyleGridLine_kMinLine <= self.gecko.${value.gecko}.mInteger);
                     debug_assert!(self.gecko.${value.gecko}.mInteger <= nsStyleGridLine_kMaxLine);
@@ -1206,30 +1209,31 @@ fn static_assert() {
     pub fn clone_grid_auto_${kind}(&self) -> longhands::grid_auto_${kind}::computed_value::T {
         crate::values::generics::grid::TrackSize::from_gecko_style_coords(&self.gecko.mGridAuto${kind.title()}Min,
                                                                      &self.gecko.mGridAuto${kind.title()}Max)
     }
 
     pub fn set_grid_template_${kind}(&mut self, v: longhands::grid_template_${kind}::computed_value::T) {
         <% self_grid = "self.gecko.mGridTemplate%s" % kind.title() %>
         use crate::gecko_bindings::structs::{nsTArray, nsStyleGridLine_kMaxLine};
-        use nsstring::nsCString;
         use std::usize;
         use crate::values::CustomIdent;
         use crate::values::generics::grid::TrackListType::Auto;
         use crate::values::generics::grid::{GridTemplateComponent, RepeatCount};
 
         #[inline]
-        fn set_line_names(servo_names: &[CustomIdent], gecko_names: &mut nsTArray<nsCString>) {
+        fn set_line_names(servo_names: &[CustomIdent], gecko_names: &mut nsTArray<structs::RefPtr<structs::nsAtom>>) {
             unsafe {
-                bindings::Gecko_ResizeTArrayForCStrings(gecko_names, servo_names.len() as u32);
+                bindings::Gecko_ResizeAtomArray(gecko_names, servo_names.len() as u32);
             }
 
             for (servo_name, gecko_name) in servo_names.iter().zip(gecko_names.iter_mut()) {
-                servo_name.0.with_str(|s| gecko_name.assign(s))
+                gecko_name.set_move(unsafe {
+                    RefPtr::from_addrefed(servo_name.0.clone().into_addrefed())
+                });
             }
         }
 
         let max_lines = nsStyleGridLine_kMaxLine as usize - 1;      // for accounting the final <line-names>
 
         let result = match v {
             GridTemplateComponent::None => ptr::null_mut(),
             GridTemplateComponent::TrackList(track) => {
@@ -1257,19 +1261,19 @@ fn static_assert() {
                     value.mRepeatAutoIndex = idx as i16;
                     // NOTE: Gecko supports only one set of values in <auto-repeat>
                     // i.e., it can only take repeat(auto-fill, [a] 10px [b]), and no more.
                     set_line_names(&auto_repeat.line_names[0], &mut value.mRepeatAutoLineNameListBefore);
                     set_line_names(&auto_repeat.line_names[1], &mut value.mRepeatAutoLineNameListAfter);
                     auto_track_size = Some(auto_repeat.track_sizes.get(0).unwrap().clone());
                 } else {
                     unsafe {
-                        bindings::Gecko_ResizeTArrayForCStrings(
+                        bindings::Gecko_ResizeAtomArray(
                             &mut value.mRepeatAutoLineNameListBefore, 0);
-                        bindings::Gecko_ResizeTArrayForCStrings(
+                        bindings::Gecko_ResizeAtomArray(
                             &mut value.mRepeatAutoLineNameListAfter, 0);
                     }
                 }
 
                 let mut line_names = track.line_names.into_iter();
                 let mut values_iter = track.values.into_iter();
                 {
                     let min_max_iter = value.mMinTrackSizingFunctions.iter_mut()
@@ -1333,37 +1337,37 @@ fn static_assert() {
 
     pub fn reset_grid_template_${kind}(&mut self, other: &Self) {
         self.copy_grid_template_${kind}_from(other)
     }
 
     pub fn clone_grid_template_${kind}(&self) -> longhands::grid_template_${kind}::computed_value::T {
         <% self_grid = "self.gecko.mGridTemplate%s" % kind.title() %>
         use crate::gecko_bindings::structs::nsTArray;
-        use nsstring::nsCString;
         use crate::values::CustomIdent;
         use crate::values::generics::grid::{GridTemplateComponent, LineNameList, RepeatCount};
         use crate::values::generics::grid::{TrackList, TrackListType, TrackListValue, TrackRepeat, TrackSize};
 
         let value = match unsafe { ${self_grid}.mPtr.as_ref() } {
             None => return GridTemplateComponent::None,
             Some(value) => value,
         };
 
         #[inline]
-        fn to_boxed_customident_slice(gecko_names: &nsTArray<nsCString>) -> Box<[CustomIdent]> {
+        fn to_boxed_customident_slice(gecko_names: &nsTArray<structs::RefPtr<structs::nsAtom>>) -> Box<[CustomIdent]> {
             let idents: Vec<CustomIdent> = gecko_names.iter().map(|gecko_name| {
-                CustomIdent(Atom::from(unsafe { gecko_name.as_str_unchecked() }))
+                CustomIdent(unsafe { Atom::from_raw(gecko_name.mRawPtr) })
             }).collect();
             idents.into_boxed_slice()
         }
 
         #[inline]
-        fn to_line_names_vec(gecko_line_names: &nsTArray<nsTArray<nsCString>>)
-            -> Vec<Box<[CustomIdent]>> {
+        fn to_line_names_vec(
+            gecko_line_names: &nsTArray<nsTArray<structs::RefPtr<structs::nsAtom>>>,
+        ) -> Vec<Box<[CustomIdent]>> {
             gecko_line_names.iter().map(|gecko_names| {
                 to_boxed_customident_slice(gecko_names)
             }).collect()
         }
 
         let repeat_auto_index = value.mRepeatAutoIndex as usize;
         if value.mIsSubgrid() {
             let mut names_vec = to_line_names_vec(&value.mLineNameLists);
--- a/servo/components/style/values/specified/position.rs
+++ b/servo/components/style/values/specified/position.rs
@@ -2,17 +2,18 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
 
 //! CSS handling for the specified value of
 //! [`position`][position]s
 //!
 //! [position]: https://drafts.csswg.org/css-backgrounds-3/#position
 
-use crate::hash::FxHashMap;
+use crate::Atom;
+use crate::selector_map::PrecomputedHashMap;
 use crate::parser::{Parse, ParserContext};
 use crate::str::HTML_SPACE_CHARACTERS;
 use crate::values::computed::LengthPercentage as ComputedLengthPercentage;
 use crate::values::computed::{Context, Percentage, ToComputedValue};
 use crate::values::generics::position::Position as GenericPosition;
 use crate::values::generics::position::ZIndex as GenericZIndex;
 use crate::values::specified::{AllowQuirks, Integer, LengthPercentage};
 use crate::Zero;
@@ -495,65 +496,65 @@ impl TemplateAreas {
     pub fn from_vec(strings: Vec<crate::OwnedStr>) -> Result<Self, ()> {
         if strings.is_empty() {
             return Err(());
         }
         let mut areas: Vec<NamedArea> = vec![];
         let mut width = 0;
         {
             let mut row = 0u32;
-            let mut area_indices = FxHashMap::<&str, usize>::default();
+            let mut area_indices = PrecomputedHashMap::<Atom, usize>::default();
             for string in &strings {
                 let mut current_area_index: Option<usize> = None;
                 row += 1;
                 let mut column = 0u32;
                 for token in TemplateAreasTokenizer(string) {
                     column += 1;
-                    let token = if let Some(token) = token? {
-                        token
+                    let name = if let Some(token) = token? {
+                        Atom::from(token)
                     } else {
                         if let Some(index) = current_area_index.take() {
                             if areas[index].columns.end != column {
                                 return Err(());
                             }
                         }
                         continue;
                     };
                     if let Some(index) = current_area_index {
-                        if &*areas[index].name == token {
+                        if areas[index].name == name {
                             if areas[index].rows.start == row {
                                 areas[index].columns.end += 1;
                             }
                             continue;
                         }
                         if areas[index].columns.end != column {
                             return Err(());
                         }
                     }
-                    if let Some(index) = area_indices.get(token).cloned() {
+                    if let Some(index) = area_indices.get(&name).cloned() {
                         if areas[index].columns.start != column || areas[index].rows.end != row {
                             return Err(());
                         }
                         areas[index].rows.end += 1;
                         current_area_index = Some(index);
                         continue;
                     }
                     let index = areas.len();
+                    assert!(area_indices.insert(name.clone(), index).is_none());
                     areas.push(NamedArea {
-                        name: token.to_owned().into(),
+                        name,
                         columns: UnsignedRange {
                             start: column,
                             end: column + 1,
                         },
                         rows: UnsignedRange {
                             start: row,
                             end: row + 1,
                         },
                     });
-                    assert!(area_indices.insert(token, index).is_none());
                     current_area_index = Some(index);
                 }
                 if let Some(index) = current_area_index {
                     if areas[index].columns.end != column + 1 {
                         assert_ne!(areas[index].rows.start, row);
                         return Err(());
                     }
                 }
@@ -624,17 +625,17 @@ pub struct UnsignedRange {
 }
 
 #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToShmem)]
 #[repr(C)]
 /// Not associated with any particular grid item, but can be referenced from the
 /// grid-placement properties.
 pub struct NamedArea {
     /// Name of the `named area`
-    pub name: crate::OwnedStr,
+    pub name: Atom,
     /// Rows of the `named area`
     pub rows: UnsignedRange,
     /// Columns of the `named area`
     pub columns: UnsignedRange,
 }
 
 /// Tokenize the string into a list of the tokens,
 /// using longest-match semantics
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -6612,13 +6612,8 @@ pub unsafe extern "C" fn Servo_CloneBasi
 pub unsafe extern "C" fn Servo_StyleArcSlice_EmptyPtr() -> *mut c_void {
     style_traits::arc_slice::ArcSlice::<u64>::leaked_empty_ptr()
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn Servo_LoadData_GetLazy(source: &url::LoadDataSource) -> *const url::LoadData {
     source.get()
 }
-
-#[no_mangle]
-pub unsafe extern "C" fn Servo_MakeOwnedStr(out: &mut style::OwnedStr, in_: &nsACString) {
-    *out = in_.to_string().into()
-}