Bug 1329169 - Use atom for animation-name property. r=xidorn
authorHiroyuki Ikezoe <hikezoe@mozilla.com>
Tue, 10 Oct 2017 17:00:28 +0900
changeset 678146 5ed2f3c94155ff0f058f059c9e5f14e6bc4e8354
parent 678145 3d20d5f37ca56295118f8031920f32d1548878d7
child 678147 24f5a87e61b7d728e2f1a487a9be4f5d1e194fad
push id83835
push userbmo:mstange@themasta.com
push dateTue, 10 Oct 2017 21:05:44 +0000
reviewersxidorn
bugs1329169
milestone58.0a1
Bug 1329169 - Use atom for animation-name property. r=xidorn MozReview-Commit-ID: 9yVWXVi1oXf
js/src/devtools/rootAnalysis/analyzeHeapWrites.js
layout/style/ServoBindingList.h
layout/style/ServoBindingTypes.h
layout/style/ServoBindings.cpp
layout/style/ServoBindings.h
layout/style/ServoBindings.toml
layout/style/ServoStyleSet.cpp
layout/style/ServoStyleSet.h
layout/style/nsAnimationManager.cpp
layout/style/nsAnimationManager.h
layout/style/nsCSSParser.cpp
layout/style/nsCSSRuleProcessor.cpp
layout/style/nsCSSRuleProcessor.h
layout/style/nsCSSRules.cpp
layout/style/nsCSSRules.h
layout/style/nsComputedDOMStyle.cpp
layout/style/nsRuleNode.cpp
layout/style/nsStyleSet.cpp
layout/style/nsStyleSet.h
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.h
--- a/js/src/devtools/rootAnalysis/analyzeHeapWrites.js
+++ b/js/src/devtools/rootAnalysis/analyzeHeapWrites.js
@@ -148,17 +148,19 @@ function treatAsSafeArgument(entry, varN
 
         // RawGeckoBorrowedNode thread-mutable parameters.
         ["Gecko_SetNodeFlags", "aNode", null],
         ["Gecko_UnsetNodeFlags", "aNode", null],
 
         // Various Servo binding out parameters. This is a mess and there needs
         // to be a way to indicate which params are out parameters, either using
         // an attribute or a naming convention.
+        ["Gecko_CopyAnimationNames", "aDest", null],
         ["Gecko_CopyFontFamilyFrom", "dst", null],
+        ["Gecko_SetAnimationName", "aStyleAnimation", null],
         ["Gecko_SetCounterStyleToName", "aPtr", null],
         ["Gecko_SetCounterStyleToSymbols", "aPtr", null],
         ["Gecko_SetCounterStyleToString", "aPtr", null],
         ["Gecko_CopyCounterStyle", "aDst", null],
         ["Gecko_SetMozBinding", "aDisplay", null],
         [/ClassOrClassList/, /aClass/, null],
         ["Gecko_GetAtomAsUTF16", "aLength", null],
         ["Gecko_CopyMozBindingFrom", "aDest", null],
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -107,17 +107,17 @@ SERVO_BINDING_FUNC(Servo_StyleSet_Insert
 SERVO_BINDING_FUNC(Servo_StyleSet_FlushStyleSheets, void, RawServoStyleSetBorrowed set,
                    RawGeckoElementBorrowedOrNull doc_elem)
 SERVO_BINDING_FUNC(Servo_StyleSet_NoteStyleSheetsChanged, void,
                    RawServoStyleSetBorrowed set,
                    bool author_style_disabled,
                    mozilla::OriginFlags changed_origins)
 SERVO_BINDING_FUNC(Servo_StyleSet_GetKeyframesForName, bool,
                    RawServoStyleSetBorrowed set,
-                   const nsACString* property,
+                   nsAtom* name,
                    nsTimingFunctionBorrowed timing_function,
                    RawGeckoKeyframeListBorrowedMut keyframe_list)
 SERVO_BINDING_FUNC(Servo_StyleSet_GetFontFaceRules, void,
                    RawServoStyleSetBorrowed set,
                    RawGeckoFontFaceRuleListBorrowedMut list)
 SERVO_BINDING_FUNC(Servo_StyleSet_GetCounterStyleRule, nsCSSCounterStyleRule*,
                    RawServoStyleSetBorrowed set, nsAtom* name)
 // This function may return nullptr or gfxFontFeatureValueSet with zero reference.
--- a/layout/style/ServoBindingTypes.h
+++ b/layout/style/ServoBindingTypes.h
@@ -162,16 +162,17 @@ DECL_OWNED_REF_TYPE_FOR(RawGeckoPresCont
 DECL_BORROWED_REF_TYPE_FOR(RawGeckoPresContext)
 DECL_BORROWED_MUT_REF_TYPE_FOR(RawGeckoServoAnimationValueList)
 DECL_BORROWED_REF_TYPE_FOR(RawGeckoServoAnimationValueList)
 DECL_BORROWED_MUT_REF_TYPE_FOR(RawGeckoKeyframeList)
 DECL_BORROWED_REF_TYPE_FOR(RawGeckoKeyframeList)
 DECL_BORROWED_MUT_REF_TYPE_FOR(RawGeckoPropertyValuePairList)
 DECL_BORROWED_REF_TYPE_FOR(RawGeckoPropertyValuePairList)
 DECL_BORROWED_MUT_REF_TYPE_FOR(RawGeckoComputedKeyframeValuesList)
+DECL_BORROWED_MUT_REF_TYPE_FOR(RawGeckoStyleAnimationList)
 DECL_BORROWED_REF_TYPE_FOR(RawGeckoStyleAnimationList)
 DECL_BORROWED_MUT_REF_TYPE_FOR(nsTimingFunction)
 DECL_BORROWED_REF_TYPE_FOR(nsTimingFunction)
 DECL_BORROWED_MUT_REF_TYPE_FOR(RawGeckoFontFaceRuleList)
 DECL_BORROWED_REF_TYPE_FOR(RawGeckoAnimationPropertySegment)
 DECL_BORROWED_REF_TYPE_FOR(RawGeckoComputedTiming)
 DECL_BORROWED_MUT_REF_TYPE_FOR(RawGeckoServoStyleRuleList)
 DECL_BORROWED_MUT_REF_TYPE_FOR(nsCSSPropertyIDSet)
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -641,16 +641,37 @@ Gecko_GetAnimationRule(RawGeckoElementBo
 bool
 Gecko_StyleAnimationsEquals(RawGeckoStyleAnimationListBorrowed aA,
                             RawGeckoStyleAnimationListBorrowed aB)
 {
   return *aA == *aB;
 }
 
 void
+Gecko_CopyAnimationNames(RawGeckoStyleAnimationListBorrowedMut aDest,
+                         RawGeckoStyleAnimationListBorrowed aSrc)
+{
+  size_t srcLength = aSrc->Length();
+  aDest->EnsureLengthAtLeast(srcLength);
+
+  for (size_t index = 0; index < srcLength; index++) {
+    (*aDest)[index].SetName((*aSrc)[index].GetName());
+  }
+}
+
+void
+Gecko_SetAnimationName(StyleAnimation* aStyleAnimation,
+                       nsAtom* aAtom)
+{
+  MOZ_ASSERT(aStyleAnimation);
+
+  aStyleAnimation->SetName(already_AddRefed<nsAtom>(aAtom));
+}
+
+void
 Gecko_UpdateAnimations(RawGeckoElementBorrowed aElement,
                        ServoStyleContextBorrowedOrNull aOldComputedData,
                        ServoStyleContextBorrowedOrNull aComputedData,
                        UpdateAnimationsTasks aTasks)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aElement);
 
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -240,16 +240,21 @@ bool Gecko_AreVisitedLinksEnabled();
 bool
 Gecko_GetAnimationRule(RawGeckoElementBorrowed aElementOrPseudo,
                        mozilla::EffectCompositor::CascadeLevel aCascadeLevel,
                        RawServoAnimationValueMapBorrowedMut aAnimationValues);
 RawServoDeclarationBlockStrongBorrowedOrNull
 Gecko_GetSMILOverrideDeclarationBlock(RawGeckoElementBorrowed element);
 bool Gecko_StyleAnimationsEquals(RawGeckoStyleAnimationListBorrowed,
                                  RawGeckoStyleAnimationListBorrowed);
+void Gecko_CopyAnimationNames(RawGeckoStyleAnimationListBorrowedMut aDest,
+                              RawGeckoStyleAnimationListBorrowed aSrc);
+// This function takes an already addrefed nsAtom
+void Gecko_SetAnimationName(mozilla::StyleAnimation* aStyleAnimation,
+                            nsAtom* aAtom);
 void Gecko_UpdateAnimations(RawGeckoElementBorrowed aElementOrPseudo,
                             ServoStyleContextBorrowedOrNull aOldComputedValues,
                             ServoStyleContextBorrowedOrNull aComputedValues,
                             mozilla::UpdateAnimationsTasks aTasks);
 bool Gecko_ElementHasAnimations(RawGeckoElementBorrowed aElementOrPseudo);
 bool Gecko_ElementHasCSSAnimations(RawGeckoElementBorrowed aElementOrPseudo);
 bool Gecko_ElementHasCSSTransitions(RawGeckoElementBorrowed aElementOrPseudo);
 size_t Gecko_ElementTransitions_Length(RawGeckoElementBorrowed aElementOrPseudo);
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -515,16 +515,17 @@ structs-types = [
     "ServoComputedData",
     "ServoStyleContext",
     "ServoStyleContextStrong",
     "EffectCompositor_CascadeLevel",
     "UpdateAnimationsTasks",
     "ParsingMode",
     "InheritTarget",
     "URLMatchingFunction",
+    "StyleAnimation",
     "StyleRuleInclusion",
     "nsStyleTransformMatrix::MatrixTransformOperator",
     "RawGeckoGfxMatrix4x4",
     "FontFamilyName",
     "mozilla::SharedFontList",
 ]
 array-types = [
     { cpp-type = "uintptr_t", rust-type = "usize" },
@@ -536,32 +537,32 @@ servo-owned-types = [
     { name = "RawServoAnimationValueMap", opaque = true },
 ]
 servo-immutable-borrow-types = [
     "RawGeckoNode",
     "RawGeckoElement",
     "RawGeckoDocument",
     "RawServoDeclarationBlockStrong",
     "RawGeckoPresContext",
-    "RawGeckoStyleAnimationList",
     "RawGeckoXBLBinding",
 ]
 servo-borrow-types = [
     "nsCSSPropertyIDSet",
     "nsCSSValue",
     "nsTimingFunction",
     "RawGeckoAnimationPropertySegment",
     "RawGeckoComputedTiming",
     "RawGeckoCSSPropertyIDList",
     "RawGeckoKeyframeList",
     "RawGeckoPropertyValuePairList",
     "RawGeckoComputedKeyframeValuesList",
     "RawGeckoFontFaceRuleList",
     "RawGeckoServoStyleRuleList",
     "RawGeckoServoAnimationValueList",
+    "RawGeckoStyleAnimationList",
     "RawGeckoStyleChildrenIterator",
 ]
 fixups = [
     # Remap the templated string type to the helper type
     { pat = "\\bnsTString<u16>", rep = "nsString" },
     # hack for gecko-owned string
     { pat = "\\b<nsString\\b", rep = "<nsStringRepr" },
 ]
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -1154,25 +1154,24 @@ ServoStyleSet::AssertTreeIsClean()
   DocumentStyleRootIterator iter(mPresContext->Document());
   while (Element* root = iter.GetNextStyleRoot()) {
     Servo_AssertTreeIsClean(root);
   }
 }
 #endif
 
 bool
-ServoStyleSet::GetKeyframesForName(const nsString& aName,
+ServoStyleSet::GetKeyframesForName(nsAtom* aName,
                                    const nsTimingFunction& aTimingFunction,
                                    nsTArray<Keyframe>& aKeyframes)
 {
   UpdateStylistIfNeeded();
 
-  NS_ConvertUTF16toUTF8 name(aName);
   return Servo_StyleSet_GetKeyframesForName(mRawSet.get(),
-                                            &name,
+                                            aName,
                                             &aTimingFunction,
                                             &aKeyframes);
 }
 
 nsTArray<ComputedKeyframeValues>
 ServoStyleSet::GetComputedKeyframeValuesFor(
   const nsTArray<Keyframe>& aKeyframes,
   Element* aElement,
--- a/layout/style/ServoStyleSet.h
+++ b/layout/style/ServoStyleSet.h
@@ -360,17 +360,17 @@ public:
   /**
    * Resolve style for the given element, and return it as a
    * ServoStyleContext.
    *
    * FIXME(emilio): Is there a point in this after bug 1367904?
    */
   already_AddRefed<ServoStyleContext> ResolveServoStyle(dom::Element* aElement);
 
-  bool GetKeyframesForName(const nsString& aName,
+  bool GetKeyframesForName(nsAtom* aName,
                            const nsTimingFunction& aTimingFunction,
                            nsTArray<Keyframe>& aKeyframes);
 
   nsTArray<ComputedKeyframeValues>
   GetComputedKeyframeValuesFor(const nsTArray<Keyframe>& aKeyframes,
                                dom::Element* aElement,
                                const ServoStyleContext* aContext);
 
--- a/layout/style/nsAnimationManager.cpp
+++ b/layout/style/nsAnimationManager.cpp
@@ -329,17 +329,17 @@ CSSAnimation::UpdateTiming(SeekFlag aSee
 NS_IMPL_CYCLE_COLLECTION(nsAnimationManager, mEventDispatcher)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsAnimationManager, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsAnimationManager, Release)
 
 // Find the matching animation by |aName| in the old list
 // of animations and remove the matched animation from the list.
 static already_AddRefed<CSSAnimation>
-PopExistingAnimation(const nsAString& aName,
+PopExistingAnimation(const nsAtom* aName,
                      nsAnimationManager::CSSAnimationCollection* aCollection)
 {
   if (!aCollection) {
     return nullptr;
   }
 
   // Animations are stored in reverse order to how they appear in the
   // animation-name property. However, we want to match animations beginning
@@ -966,17 +966,17 @@ BuildAnimations(nsPresContext* aPresCont
   for (size_t animIdx = aStyleAnimationNameCount; animIdx-- != 0;) {
     const StyleAnimation& src = aStyleAnimations[animIdx];
 
     // CSS Animations whose animation-name does not match a @keyframes rule do
     // not generate animation events. This includes when the animation-name is
     // "none" which is represented by an empty name in the StyleAnimation.
     // Since such animations neither affect style nor dispatch events, we do
     // not generate a corresponding CSSAnimation for them.
-    if (src.GetName().IsEmpty()) {
+    if (src.GetName() == nsGkAtoms::_empty) {
       continue;
     }
 
     RefPtr<CSSAnimation> dest = BuildAnimation(aPresContext,
                                                aTarget,
                                                src,
                                                aBuilder,
                                                aCollection);
@@ -1052,17 +1052,17 @@ nsAnimationManager::DoUpdateAnimations(
   // Likewise, when we initially construct frames, we're not in a
   // style change, but also not in an animation restyle.
 
   CSSAnimationCollection* collection =
     CSSAnimationCollection::GetAnimationCollection(aTarget.mElement,
                                                    aTarget.mPseudoType);
   if (!collection &&
       aStyleDisplay.mAnimationNameCount == 1 &&
-      aStyleDisplay.mAnimations[0].GetName().IsEmpty()) {
+      aStyleDisplay.mAnimations[0].GetName() == nsGkAtoms::_empty) {
     return;
   }
 
   nsAutoAnimationMutationBatch mb(aTarget.mElement->OwnerDoc());
 
   // Build the updated animations list, extracting matching animations from
   // the existing collection as we go.
   OwningCSSAnimationPtrArray newAnimations;
--- a/layout/style/nsAnimationManager.h
+++ b/layout/style/nsAnimationManager.h
@@ -38,27 +38,27 @@ struct AnimationEventInfo {
   RefPtr<dom::Element> mElement;
   RefPtr<dom::Animation> mAnimation;
   InternalAnimationEvent mEvent;
   TimeStamp mTimeStamp;
 
   AnimationEventInfo(dom::Element* aElement,
                      CSSPseudoElementType aPseudoType,
                      EventMessage aMessage,
-                     const nsAString& aAnimationName,
+                     nsAtom* aAnimationName,
                      const StickyTimeDuration& aElapsedTime,
                      const TimeStamp& aTimeStamp,
                      dom::Animation* aAnimation)
     : mElement(aElement)
     , mAnimation(aAnimation)
     , mEvent(true, aMessage)
     , mTimeStamp(aTimeStamp)
   {
     // XXX Looks like nobody initialize WidgetEvent::time
-    mEvent.mAnimationName = aAnimationName;
+    aAnimationName->ToString(mEvent.mAnimationName);
     mEvent.mElapsedTime =
       nsRFPService::ReduceTimePrecisionAsSecs(aElapsedTime.ToSeconds());
     mEvent.mPseudoElement =
       AnimationCollection<dom::CSSAnimation>::PseudoTypeAsString(aPseudoType);
   }
 
   // InternalAnimationEvent doesn't support copy-construction, so we need
   // to ourselves in order to work with nsTArray
@@ -73,43 +73,45 @@ struct AnimationEventInfo {
 };
 
 namespace dom {
 
 class CSSAnimation final : public Animation
 {
 public:
  explicit CSSAnimation(nsIGlobalObject* aGlobal,
-                       const nsAString& aAnimationName)
+                       nsAtom* aAnimationName)
     : dom::Animation(aGlobal)
     , mAnimationName(aAnimationName)
     , mIsStylePaused(false)
     , mPauseShouldStick(false)
     , mNeedsNewAnimationIndexWhenRun(false)
     , mPreviousPhase(ComputedTiming::AnimationPhase::Idle)
     , mPreviousIteration(0)
   {
     // We might need to drop this assertion once we add a script-accessible
     // constructor but for animations generated from CSS markup the
     // animation-name should never be empty.
-    MOZ_ASSERT(!mAnimationName.IsEmpty(), "animation-name should not be empty");
+    MOZ_ASSERT(mAnimationName != nsGkAtoms::_empty,
+               "animation-name should not be 'none'");
   }
 
   JSObject* WrapObject(JSContext* aCx,
                        JS::Handle<JSObject*> aGivenProto) override;
 
   CSSAnimation* AsCSSAnimation() override { return this; }
   const CSSAnimation* AsCSSAnimation() const override { return this; }
 
   // CSSAnimation interface
-  void GetAnimationName(nsString& aRetVal) const { aRetVal = mAnimationName; }
+  void GetAnimationName(nsString& aRetVal) const
+  {
+    mAnimationName->ToString(aRetVal);
+  }
 
-  // Alternative to GetAnimationName that returns a reference to the member
-  // for more efficient internal usage.
-  const nsString& AnimationName() const { return mAnimationName; }
+  nsAtom* AnimationName() const { return mAnimationName; }
 
   // Animation interface overrides
   virtual Promise* GetReady(ErrorResult& aRv) override;
   virtual void Play(ErrorResult& aRv, LimitBehavior aLimitBehavior) override;
   virtual void Pause(ErrorResult& aRv) override;
 
   // NOTE: tabbrowser.xml currently relies on the fact that reading the
   // currentTime of a CSSAnimation does *not* flush style (whereas reading the
@@ -198,17 +200,17 @@ protected:
   // which case it is the absolute value of that delay.
   // This is used for setting the elapsedTime member of CSS AnimationEvents.
   TimeDuration InitialAdvance() const {
     return mEffect ?
            std::max(TimeDuration(), mEffect->SpecifiedTiming().Delay() * -1) :
            TimeDuration();
   }
 
-  nsString mAnimationName;
+  RefPtr<nsAtom> mAnimationName;
 
   // The (pseudo-)element whose computed animation-name refers to this
   // animation (if any).
   //
   // This is used for determining the relative composite order of animations
   // generated from CSS markup.
   //
   // Typically this will be the same as the target element of the keyframe
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -4276,18 +4276,18 @@ CSSParserImpl::ParseKeyframesRule(RuleAp
 
   nsString name(mToken.mIdent);
 
   if (!ExpectSymbol('{', true)) {
     REPORT_UNEXPECTED_TOKEN(PEKeyframeBrace);
     return false;
   }
 
-  RefPtr<nsCSSKeyframesRule> rule = new nsCSSKeyframesRule(name,
-                                                             linenum, colnum);
+  RefPtr<nsCSSKeyframesRule> rule =
+    new nsCSSKeyframesRule(NS_Atomize(name), linenum, colnum);
 
   while (!ExpectSymbol('}', true)) {
     RefPtr<nsCSSKeyframeRule> kid = ParseKeyframeRule();
     if (kid) {
       rule->AppendStyleRule(kid);
     } else {
       OUTPUT_ERROR();
       SkipRuleSet(true);
--- a/layout/style/nsCSSRuleProcessor.cpp
+++ b/layout/style/nsCSSRuleProcessor.cpp
@@ -889,17 +889,18 @@ struct RuleCascadeData {
 #endif
 
   nsTArray<nsFontFaceRuleContainer> mFontFaceRules;
   nsTArray<nsCSSKeyframesRule*> mKeyframesRules;
   nsTArray<nsCSSFontFeatureValuesRule*> mFontFeatureValuesRules;
   nsTArray<nsCSSPageRule*> mPageRules;
   nsTArray<nsCSSCounterStyleRule*> mCounterStyleRules;
 
-  nsDataHashtable<nsStringHashKey, nsCSSKeyframesRule*> mKeyframesRuleTable;
+  nsDataHashtable<nsRefPtrHashKey<const nsAtom>,
+                  nsCSSKeyframesRule*> mKeyframesRuleTable;
   // The hashtable doesn't need to hold a strong reference to the name
   // atom, because nsCSSCounterStyleRule always does. If the name changes
   // we need to discard this table and rebuild it anyway.
   nsDataHashtable<nsPtrHashKey<nsAtom>,
                   nsCSSCounterStyleRule*> mCounterStyleRuleTable;
 
   // Looks up or creates the appropriate list in |mAttributeSelectors|.
   // Returns null only on allocation failure.
@@ -947,27 +948,17 @@ RuleCascadeData::SizeOfIncludingThis(Mal
   n += SizeOfRuleHashTable(mXULTreeRules, aMallocSizeOf);
 #endif
 
   n += mFontFaceRules.ShallowSizeOfExcludingThis(aMallocSizeOf);
   n += mKeyframesRules.ShallowSizeOfExcludingThis(aMallocSizeOf);
   n += mFontFeatureValuesRules.ShallowSizeOfExcludingThis(aMallocSizeOf);
   n += mPageRules.ShallowSizeOfExcludingThis(aMallocSizeOf);
   n += mCounterStyleRules.ShallowSizeOfExcludingThis(aMallocSizeOf);
-
   n += mKeyframesRuleTable.ShallowSizeOfExcludingThis(aMallocSizeOf);
-  for (auto iter = mKeyframesRuleTable.ConstIter(); !iter.Done(); iter.Next()) {
-    // We don't own the nsCSSKeyframesRule objects so we don't count them. We
-    // do care about the size of the keys' nsAString members' buffers though.
-    //
-    // Note that we depend on nsStringHashKey::GetKey() returning a reference,
-    // since otherwise aKey would be a copy of the string key and we would not
-    // be measuring the right object here.
-    n += iter.Key().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
-  }
 
   return n;
 }
 
 nsTArray<SelectorPair>*
 RuleCascadeData::AttributeListFor(nsAtom* aAttribute)
 {
   auto entry = static_cast<AtomSelectorEntry*>
@@ -3098,17 +3089,17 @@ nsCSSRuleProcessor::AppendFontFaceRules(
       return false;
   }
 
   return true;
 }
 
 nsCSSKeyframesRule*
 nsCSSRuleProcessor::KeyframesRuleForName(nsPresContext* aPresContext,
-                                         const nsString& aName)
+                                         const nsAtom* aName)
 {
   RuleCascadeData* cascade = GetRuleCascade(aPresContext);
 
   if (cascade) {
     return cascade->mKeyframesRuleTable.Get(aName);
   }
 
   return nullptr;
--- a/layout/style/nsCSSRuleProcessor.h
+++ b/layout/style/nsCSSRuleProcessor.h
@@ -207,17 +207,17 @@ public:
     const MOZ_MUST_OVERRIDE override;
 
   // Append all the currently-active font face rules to aArray.  Return
   // true for success and false for failure.
   bool AppendFontFaceRules(nsPresContext* aPresContext,
                            nsTArray<nsFontFaceRuleContainer>& aArray);
 
   nsCSSKeyframesRule* KeyframesRuleForName(nsPresContext* aPresContext,
-                                           const nsString& aName);
+                                           const nsAtom* aName);
 
   nsCSSCounterStyleRule* CounterStyleRuleForName(nsPresContext* aPresContext,
                                                  nsAtom* aName);
 
   bool AppendPageRules(nsPresContext* aPresContext,
                        nsTArray<nsCSSPageRule*>& aArray);
 
   bool AppendFontFeatureValuesRules(nsPresContext* aPresContext,
--- a/layout/style/nsCSSRules.cpp
+++ b/layout/style/nsCSSRules.cpp
@@ -1721,57 +1721,57 @@ void
 nsCSSKeyframesRule::List(FILE* out, int32_t aIndent) const
 {
   nsAutoCString indentStr;
   for (int32_t indent = aIndent; --indent >= 0; ) {
     indentStr.AppendLiteral("  ");
   }
 
   fprintf_stderr(out, "%s@keyframes %s {\n",
-                 indentStr.get(), NS_ConvertUTF16toUTF8(mName).get());
+                 indentStr.get(), nsAtomCString(mName).get());
 
   GroupRule::List(out, aIndent);
 
   fprintf_stderr(out, "%s}\n", indentStr.get());
 }
 #endif
 
 void
 nsCSSKeyframesRule::GetCssTextImpl(nsAString& aCssText) const
 {
   aCssText.AssignLiteral("@keyframes ");
-  aCssText.Append(mName);
+  aCssText.Append(nsDependentAtomString(mName));
   aCssText.AppendLiteral(" {\n");
   nsAutoString tmp;
   for (const Rule* rule : GeckoRules()) {
     static_cast<const nsCSSKeyframeRule*>(rule)->GetCssText(tmp);
     aCssText.Append(tmp);
     aCssText.Append('\n');
   }
   aCssText.Append('}');
 }
 
 NS_IMETHODIMP
 nsCSSKeyframesRule::GetName(nsAString& aName)
 {
-  aName = mName;
+  mName->ToString(aName);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCSSKeyframesRule::SetName(const nsAString& aName)
 {
-  if (mName == aName) {
+  if (mName->Equals(aName)) {
     return NS_OK;
   }
 
   nsIDocument* doc = GetDocument();
   MOZ_AUTO_DOC_UPDATE(doc, UPDATE_STYLE, true);
 
-  mName = aName;
+  mName = NS_Atomize(aName);
 
   if (StyleSheet* sheet = GetStyleSheet()) {
     sheet->AsGecko()->SetModifiedByChildRule();
     if (doc) {
       doc->StyleRuleChanged(sheet, this);
     }
   }
 
--- a/layout/style/nsCSSRules.h
+++ b/layout/style/nsCSSRules.h
@@ -291,17 +291,17 @@ private:
   RefPtr<mozilla::css::Declaration>          mDeclaration;
   // lazily created when needed:
   RefPtr<nsCSSKeyframeStyleDeclaration>    mDOMDeclaration;
 };
 
 class nsCSSKeyframesRule final : public mozilla::dom::CSSKeyframesRule
 {
 public:
-  nsCSSKeyframesRule(const nsAString& aName,
+  nsCSSKeyframesRule(already_AddRefed<nsAtom> aName,
                      uint32_t aLineNumber, uint32_t aColumnNumber)
     : mozilla::dom::CSSKeyframesRule(aLineNumber, aColumnNumber)
     , mName(aName)
   {
   }
 private:
   nsCSSKeyframesRule(const nsCSSKeyframesRule& aCopy);
   ~nsCSSKeyframesRule();
@@ -321,24 +321,24 @@ public:
   NS_IMETHOD DeleteRule(const nsAString& aKey) final;
   using nsIDOMCSSKeyframesRule::FindRule;
 
   // WebIDL interface
   void GetCssTextImpl(nsAString& aCssText) const final;
   mozilla::dom::CSSRuleList* CssRules() final { return GroupRule::CssRules(); }
   nsCSSKeyframeRule* FindRule(const nsAString& aKey) final;
 
-  const nsString& GetName() { return mName; }
+  const nsAtom* GetName() const { return mName; }
 
   virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
 
 private:
   uint32_t FindRuleIndexForKey(const nsAString& aKey);
 
-  nsString                                   mName;
+  RefPtr<nsAtom> mName;
 };
 
 class nsCSSPageRule;
 
 class nsCSSPageStyleDeclaration final : public nsDOMCSSDeclaration
 {
 public:
   explicit nsCSSPageStyleDeclaration(nsCSSPageRule *aRule);
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -6862,22 +6862,23 @@ nsComputedDOMStyle::DoGetAnimationName()
 
   MOZ_ASSERT(display->mAnimationNameCount > 0,
              "first item must be explicit");
   uint32_t i = 0;
   do {
     const StyleAnimation *animation = &display->mAnimations[i];
     RefPtr<nsROCSSPrimitiveValue> property = new nsROCSSPrimitiveValue;
 
-    const nsString& name = animation->GetName();
-    if (name.IsEmpty()) {
+    nsAtom* name = animation->GetName();
+    if (name == nsGkAtoms::_empty) {
       property->SetIdent(eCSSKeyword_none);
     } else {
+      nsDependentAtomString nameStr(name);
       nsAutoString escaped;
-      nsStyleUtil::AppendEscapedCSSIdent(animation->GetName(), escaped);
+      nsStyleUtil::AppendEscapedCSSIdent(nameStr, escaped);
       property->SetString(escaped); // really want SetIdent
     }
     valueList->AppendCSSValue(property.forget());
   } while (++i < display->mAnimationNameCount);
 
   return valueList.forget();
 }
 
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -5896,28 +5896,27 @@ nsRuleNode::ComputeDisplayData(void* aSt
     } else if (animName.unit == eCSSUnit_Inherit) {
       MOZ_ASSERT(i < parentDisplay->mAnimationNameCount,
                  "animName.num computed incorrectly");
       MOZ_ASSERT(!conditions.Cacheable(),
                  "should have made conditions.Cacheable() false above");
       animation->SetName(parentDisplay->mAnimations[i].GetName());
     } else if (animName.unit == eCSSUnit_Initial ||
                animName.unit == eCSSUnit_Unset) {
-      animation->SetName(EmptyString());
+      animation->SetName(nsGkAtoms::_empty);
     } else if (animName.list) {
       switch (animName.list->mValue.GetUnit()) {
         case eCSSUnit_String:
         case eCSSUnit_Ident: {
-          nsDependentString
-            nameStr(animName.list->mValue.GetStringBufferValue());
-          animation->SetName(nameStr);
+          animation->SetName(
+            NS_Atomize(animName.list->mValue.GetStringBufferValue()));
           break;
         }
         case eCSSUnit_None: {
-          animation->SetName(EmptyString());
+          animation->SetName(nsGkAtoms::_empty);
           break;
         }
         default:
           MOZ_ASSERT(false, "Invalid animation-name unit");
       }
     }
 
     if (i >= animTimingFunction.num) {
--- a/layout/style/nsStyleSet.cpp
+++ b/layout/style/nsStyleSet.cpp
@@ -2236,17 +2236,17 @@ nsStyleSet::AppendFontFaceRules(nsTArray
                                     (mRuleProcessors[gCSSSheetTypes[i]].get());
     if (ruleProc && !ruleProc->AppendFontFaceRules(presContext, aArray))
       return false;
   }
   return true;
 }
 
 nsCSSKeyframesRule*
-nsStyleSet::KeyframesRuleForName(const nsString& aName)
+nsStyleSet::KeyframesRuleForName(nsAtom* aName)
 {
   NS_ENSURE_FALSE(mInShutdown, nullptr);
   NS_ASSERTION(mBatching == 0, "rule processors out of date");
 
   nsPresContext* presContext = PresContext();
   for (uint32_t i = ArrayLength(gCSSSheetTypes); i-- != 0; ) {
     if (gCSSSheetTypes[i] == SheetType::ScopedDoc)
       continue;
--- a/layout/style/nsStyleSet.h
+++ b/layout/style/nsStyleSet.h
@@ -310,17 +310,17 @@ class nsStyleSet final
                             nsICSSPseudoComparator* aComparator);
 #endif
 
   // Append all the currently-active font face rules to aArray.  Return
   // true for success and false for failure.
   bool AppendFontFaceRules(nsTArray<nsFontFaceRuleContainer>& aArray);
 
   // Return the winning (in the cascade) @keyframes rule for the given name.
-  nsCSSKeyframesRule* KeyframesRuleForName(const nsString& aName);
+  nsCSSKeyframesRule* KeyframesRuleForName(nsAtom* aName);
 
   // Return the winning (in the cascade) @counter-style rule for the given name.
   nsCSSCounterStyleRule* CounterStyleRuleForName(nsAtom* aName);
 
   // Return gfxFontFeatureValueSet from font feature values rules.
   already_AddRefed<gfxFontFeatureValueSet> BuildFontFeatureValueSet();
 
   // Append all the currently-active font feature values rules to aArray.
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -3431,17 +3431,17 @@ StyleAnimation::StyleAnimation(const Sty
 }
 
 void
 StyleAnimation::SetInitialValues()
 {
   mTimingFunction = nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE);
   mDuration = 0.0;
   mDelay = 0.0;
-  mName = EmptyString();
+  mName = nsGkAtoms::_empty;
   mDirection = dom::PlaybackDirection::Normal;
   mFillMode = dom::FillMode::None;
   mPlayState = NS_STYLE_ANIMATION_PLAY_STATE_RUNNING;
   mIterationCount = 1.0f;
 }
 
 bool
 StyleAnimation::operator==(const StyleAnimation& aOther) const
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -2305,44 +2305,45 @@ struct StyleAnimation
 
   void SetInitialValues();
 
   // Delay and Duration are in milliseconds
 
   const nsTimingFunction& GetTimingFunction() const { return mTimingFunction; }
   float GetDelay() const { return mDelay; }
   float GetDuration() const { return mDuration; }
-  const nsString& GetName() const { return mName; }
+  nsAtom* GetName() const { return mName; }
   dom::PlaybackDirection GetDirection() const { return mDirection; }
   dom::FillMode GetFillMode() const { return mFillMode; }
   uint8_t GetPlayState() const { return mPlayState; }
   float GetIterationCount() const { return mIterationCount; }
 
   void SetTimingFunction(const nsTimingFunction& aTimingFunction)
     { mTimingFunction = aTimingFunction; }
   void SetDelay(float aDelay) { mDelay = aDelay; }
   void SetDuration(float aDuration) { mDuration = aDuration; }
-  void SetName(const nsAString& aName) { mName = aName; }
+  void SetName(already_AddRefed<nsAtom> aName) { mName = aName; }
+  void SetName(nsAtom* aName) { mName = aName; }
   void SetDirection(dom::PlaybackDirection aDirection) { mDirection = aDirection; }
   void SetFillMode(dom::FillMode aFillMode) { mFillMode = aFillMode; }
   void SetPlayState(uint8_t aPlayState) { mPlayState = aPlayState; }
   void SetIterationCount(float aIterationCount)
     { mIterationCount = aIterationCount; }
 
   nsTimingFunction& TimingFunctionSlot() { return mTimingFunction; }
 
   bool operator==(const StyleAnimation& aOther) const;
   bool operator!=(const StyleAnimation& aOther) const
     { return !(*this == aOther); }
 
 private:
   nsTimingFunction mTimingFunction;
   float mDuration;
   float mDelay;
-  nsString mName; // empty string for 'none'
+  RefPtr<nsAtom> mName; // nsGkAtoms::_empty for 'none'
   dom::PlaybackDirection mDirection;
   dom::FillMode mFillMode;
   uint8_t mPlayState;
   float mIterationCount; // mozilla::PositiveInfinity<float>() means infinite
 };
 
 class StyleBasicShape final
 {