Bug 1196114 - Part 5: Store performce warning information as enum type. r?birtles draft
authorHiroyuki Ikezoe <hiikezoe@mozilla-japan.org>
Fri, 04 Mar 2016 17:54:25 +0900
changeset 336876 64420a5ad482e3c1696a69ee98ce7f333257d4af
parent 336801 6a696ce77605caeb338966655b935ab652f1cafe
child 515519 67a44e9dfd92212e6b8a602d1e459ed99a739aee
push id12205
push userhiikezoe@mozilla-japan.org
push dateFri, 04 Mar 2016 10:23:01 +0000
reviewersbirtles
bugs1196114
milestone47.0a1
Bug 1196114 - Part 5: Store performce warning information as enum type. r?birtles Each warning message is generated only when getPropertyState() is called. MozReview-Commit-ID: C03ZSvPv9ff
dom/animation/AnimationPerformanceWarning.cpp
dom/animation/AnimationPerformanceWarning.h
dom/animation/EffectCompositor.cpp
dom/animation/EffectCompositor.h
dom/animation/KeyframeEffect.cpp
dom/animation/KeyframeEffect.h
dom/animation/moz.build
layout/base/nsDisplayList.cpp
new file mode 100644
--- /dev/null
+++ b/dom/animation/AnimationPerformanceWarning.cpp
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "AnimationPerformanceWarning.h"
+
+#include "nsContentUtils.h"
+
+namespace mozilla {
+
+bool
+AnimationPerformanceWarning::ToLocalizedString(
+  nsXPIDLString& aLocalizedString) const
+{
+  const char* key = nullptr;
+
+  switch (mType) {
+    case Type::ContentTooLarge:
+    {
+      MOZ_ASSERT(mParams && mParams->Length() == 7,
+                 "Parameter's length should be 7 for ContentTooLarge");
+
+      MOZ_ASSERT(mParams->Length() <= kMaxParamsForLocalization,
+                 "Parameter's length should be less than "
+                 "kMaxParamsForLocalization");
+      // We can pass an array of parameters whose length is greater than 7 to
+      // nsContentUtils::FormatLocalizedString because
+      // nsTextFormatter drops those extra parameters in the end.
+      nsAutoString strings[kMaxParamsForLocalization];
+      const char16_t* charParams[kMaxParamsForLocalization];
+
+      for (size_t i = 0, n = mParams->Length(); i < n; i++) {
+        strings[i].AppendInt((*mParams)[i]);
+        charParams[i] = strings[i].get();
+      }
+
+      nsresult rv = nsContentUtils::FormatLocalizedString(
+        nsContentUtils::eLAYOUT_PROPERTIES,
+        "AnimationWarningContentTooLarge",
+        charParams,
+        aLocalizedString);
+      return NS_SUCCEEDED(rv);
+    }
+    case Type::TransformBackfaceVisibilityHidden:
+      key = "AnimationWarningTransformBackfaceVisibilityHidden";
+      break;
+    case Type::TransformPreserve3D:
+      key = "AnimationWarningTransformPreserve3D";
+      break;
+    case Type::TransformSVG:
+      key = "AnimationWarningTransformSVG";
+      break;
+    case Type::TransformFrameInactive:
+      key = "AnimationWarningTransformFrameInactive";
+      break;
+    case Type::OpacityFrameInactive:
+      key = "AnimationWarningOpacityFrameInactive";
+      break;
+    case Type::WithGeometricProperties:
+      key = "AnimationWarningWithGeometricProperties";
+      break;
+  }
+
+  nsresult rv =
+    nsContentUtils::GetLocalizedString(nsContentUtils::eLAYOUT_PROPERTIES,
+                                       key, aLocalizedString);
+  return NS_SUCCEEDED(rv);
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/animation/AnimationPerformanceWarning.h
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_AnimationPerformanceWarning_h
+#define mozilla_dom_AnimationPerformanceWarning_h
+
+#include "mozilla/InitializerList.h"
+
+class nsXPIDLString;
+
+namespace mozilla {
+
+// Represents the reason why we can't run the CSS property on the compositor.
+struct AnimationPerformanceWarning
+{
+  enum class Type : uint8_t {
+    ContentTooLarge,
+    TransformBackfaceVisibilityHidden,
+    TransformPreserve3D,
+    TransformSVG,
+    TransformFrameInactive,
+    OpacityFrameInactive,
+    WithGeometricProperties
+  };
+
+  explicit AnimationPerformanceWarning(Type aType)
+    : mType(aType) { }
+
+  AnimationPerformanceWarning(Type aType,
+                              std::initializer_list<int32_t> aParams)
+    : mType(aType)
+  {
+    // FIXME:  Once std::initializer_list::size() become a constexpr function,
+    // we should use static_assert here.
+    MOZ_ASSERT(aParams.size() <= kMaxParamsForLocalization,
+      "The length of parameters should be less than "
+      "kMaxParamsForLocalization");
+    mParams.emplace(aParams);
+  }
+
+  // Maximum number of parameters passed to
+  // nsContentUtils::FormatLocalizedString to localize warning messages.
+  //
+  // NOTE: This constexpr can't be forward declared, so if you want to use
+  // this variable, please include this header file directly.
+  // This value is the same as the limit of nsStringBundle::FormatString.
+  // See the implementation of nsStringBundle::FormatString.
+  static MOZ_CONSTEXPR_VAR uint8_t kMaxParamsForLocalization = 10;
+
+  // Indicates why this property could not be animated on the compositor.
+  Type mType;
+
+  // Optional parameters that may be used for localization.
+  Maybe<nsTArray<int32_t>> mParams;
+
+  bool ToLocalizedString(nsXPIDLString& aLocalizedString) const;
+
+  bool operator==(const AnimationPerformanceWarning& aOther) const
+  {
+    return mType == aOther.mType &&
+           mParams == aOther.mParams;
+  }
+  bool operator!=(const AnimationPerformanceWarning& aOther) const
+  {
+    return !(*this == aOther);
+  }
+};
+
+} // namespace mozilla
+
+#endif // mozilla_dom_AnimationPerformanceWarning_h
--- a/dom/animation/EffectCompositor.cpp
+++ b/dom/animation/EffectCompositor.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "EffectCompositor.h"
 
 #include "mozilla/dom/Animation.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/KeyframeEffect.h" // For KeyframeEffectReadOnly
 #include "mozilla/AnimationUtils.h"
+#include "mozilla/AnimationPerformanceWarning.h"
 #include "mozilla/EffectSet.h"
 #include "mozilla/InitializerList.h"
 #include "mozilla/LayerAnimationInfo.h"
 #include "mozilla/RestyleManagerHandle.h"
 #include "mozilla/RestyleManagerHandleInlines.h"
 #include "nsComputedDOMStyle.h" // nsComputedDOMStyle::GetPresShellForContent
 #include "nsCSSPropertySet.h"
 #include "nsCSSProps.h"
@@ -104,24 +105,24 @@ FindAnimationsForCompositor(const nsIFra
   for (KeyframeEffectReadOnly* effect : *effects) {
     MOZ_ASSERT(effect && effect->GetAnimation());
     Animation* animation = effect->GetAnimation();
 
     if (!animation->IsPlaying()) {
       continue;
     }
 
-    nsAutoString performanceWarning;
+    AnimationPerformanceWarning::Type warningType;
     if (effect->ShouldBlockCompositorAnimations(aFrame,
-                                                performanceWarning)) {
+                                                warningType)) {
       if (aMatches) {
         aMatches->Clear();
       }
-      effect->SetPerformanceWarning(aProperty,
-                                    performanceWarning);
+      effect->SetPerformanceWarning(
+        aProperty, AnimationPerformanceWarning(warningType));
       return false;
     }
 
     if (!effect->HasAnimationOfProperty(aProperty)) {
       continue;
     }
 
     if (aMatches) {
@@ -716,27 +717,28 @@ EffectCompositor::GetPresContext(Element
   nsIPresShell* shell = nsComputedDOMStyle::GetPresShellForContent(aElement);
   if (!shell) {
     return nullptr;
   }
   return shell->GetPresContext();
 }
 
 /* static */ void
-EffectCompositor::SetPerformanceWarning(const nsIFrame *aFrame,
-                                        nsCSSProperty aProperty,
-                                        const nsAString& aMessage)
+EffectCompositor::SetPerformanceWarning(
+  const nsIFrame *aFrame,
+  nsCSSProperty aProperty,
+  const AnimationPerformanceWarning& aWarning)
 {
   EffectSet* effects = EffectSet::GetEffectSet(aFrame);
   if (!effects) {
     return;
   }
 
   for (KeyframeEffectReadOnly* effect : *effects) {
-    effect->SetPerformanceWarning(aProperty, aMessage);
+    effect->SetPerformanceWarning(aProperty, aWarning);
   }
 }
 
 // ---------------------------------------------------------
 //
 // Nested class: AnimationStyleRuleProcessor
 //
 // ---------------------------------------------------------
--- a/dom/animation/EffectCompositor.h
+++ b/dom/animation/EffectCompositor.h
@@ -25,16 +25,17 @@ class nsIStyleRule;
 class nsPresContext;
 class nsStyleContext;
 
 namespace mozilla {
 
 class EffectSet;
 class RestyleTracker;
 enum class CSSPseudoElementType : uint8_t;
+struct AnimationPerformanceWarning;
 
 namespace dom {
 class Animation;
 class Element;
 }
 
 class EffectCompositor
 {
@@ -182,21 +183,22 @@ public:
   // AnimationCollection), *not* the generated content.
   //
   // Returns an empty result when a suitable element cannot be found including
   // when the frame represents a pseudo-element on which we do not support
   // animations.
   static Maybe<Pair<dom::Element*, CSSPseudoElementType>>
   GetAnimationElementAndPseudoForFrame(const nsIFrame* aFrame);
 
-  // Associates a warning message with effects on |aFrame| if the effect
-  // has |aProperty|.
-  static void SetPerformanceWarning(const nsIFrame* aFrame,
-                                    nsCSSProperty aProperty,
-                                    const nsAString& aMessage);
+  // Associates a performance warning with effects on |aFrame| that animates
+  // |aProperty|.
+  static void SetPerformanceWarning(
+    const nsIFrame* aFrame,
+    nsCSSProperty aProperty,
+    const AnimationPerformanceWarning& aWarning);
 
 private:
   ~EffectCompositor() = default;
 
   // Rebuilds the animation rule corresponding to |aCascadeLevel| on the
   // EffectSet associated with the specified (pseudo-)element.
   static void ComposeAnimationRule(dom::Element* aElement,
                                    CSSPseudoElementType aPseudoType,
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -1888,18 +1888,20 @@ KeyframeEffectReadOnly::GetPropertyState
       continue;
     }
 
     AnimationPropertyState state;
     state.mProperty.Construct(
       NS_ConvertASCIItoUTF16(nsCSSProps::GetStringValue(property.mProperty)));
     state.mRunningOnCompositor.Construct(property.mIsRunningOnCompositor);
 
-    if (property.mPerformanceWarning.isSome()) {
-      state.mWarning.Construct(property.mPerformanceWarning.value());
+    nsXPIDLString localizedString;
+    if (property.mPerformanceWarning &&
+        property.mPerformanceWarning->ToLocalizedString(localizedString)) {
+      state.mWarning.Construct(localizedString);
     }
 
     aStates.AppendElement(state);
   }
 }
 
 /* static */ const TimeDuration
 KeyframeEffectReadOnly::OverflowRegionRefreshInterval()
@@ -2094,111 +2096,97 @@ KeyframeEffectReadOnly::IsGeometricPrope
     default:
       return false;
   }
 }
 
 /* static */ bool
 KeyframeEffectReadOnly::CanAnimateTransformOnCompositor(
   const nsIFrame* aFrame,
-  nsAString& aPerformanceWarning)
+  AnimationPerformanceWarning::Type& aPerformanceWarning)
 {
   // Disallow OMTA for preserve-3d transform. Note that we check the style property
   // rather than Extend3DContext() since that can recurse back into this function
   // via HasOpacity(). See bug 779598.
   if (aFrame->Combines3DTransformWithAncestors() ||
       aFrame->StyleDisplay()->mTransformStyle == NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D) {
-    nsXPIDLString localizedMessage;
-    nsContentUtils::GetLocalizedString(
-      nsContentUtils::eLAYOUT_PROPERTIES,
-      "AnimationWarningTransformPreserve3D",
-      localizedMessage);
-    aPerformanceWarning = localizedMessage;
+    aPerformanceWarning = AnimationPerformanceWarning::Type::TransformPreserve3D;
     return false;
   }
   // Note that testing BackfaceIsHidden() is not a sufficient test for
   // what we need for animating backface-visibility correctly if we
   // remove the above test for Extend3DContext(); that would require
   // looking at backface-visibility on descendants as well. See bug 1186204.
   if (aFrame->StyleDisplay()->BackfaceIsHidden()) {
-    nsXPIDLString localizedMessage;
-    nsContentUtils::GetLocalizedString(
-      nsContentUtils::eLAYOUT_PROPERTIES,
-      "AnimationWarningTransformBackfaceVisibilityHidden",
-      localizedMessage);
-    aPerformanceWarning = localizedMessage;
+    aPerformanceWarning =
+      AnimationPerformanceWarning::Type::TransformBackfaceVisibilityHidden;
     return false;
   }
   // Async 'transform' animations of aFrames with SVG transforms is not
   // supported.  See bug 779599.
   if (aFrame->IsSVGTransformed()) {
-    nsXPIDLString localizedMessage;
-    nsContentUtils::GetLocalizedString(
-      nsContentUtils::eLAYOUT_PROPERTIES,
-      "AnimationWarningTransformSVG",
-      localizedMessage);
-    aPerformanceWarning = localizedMessage;
+    aPerformanceWarning = AnimationPerformanceWarning::Type::TransformSVG;
     return false;
   }
 
   return true;
 }
 
 bool
 KeyframeEffectReadOnly::ShouldBlockCompositorAnimations(
   const nsIFrame* aFrame,
-  nsAString& aPerformanceWarning) const
+  AnimationPerformanceWarning::Type& aPerformanceWarning) const
 {
   // We currently only expect this method to be called when this effect
   // is attached to a playing Animation. If that ever changes we'll need
   // to update this to only return true when that is the case since paused,
   // filling, cancelled Animations etc. shouldn't stop other Animations from
   // running on the compositor.
   MOZ_ASSERT(mAnimation && mAnimation->IsPlaying());
 
   for (const AnimationProperty& property : mProperties) {
     // If a property is overridden in the CSS cascade, it should not block other
     // animations from running on the compositor.
     if (!property.mWinsInCascade) {
       continue;
     }
     // Check for geometric properties
     if (IsGeometricProperty(property.mProperty)) {
-      nsXPIDLString localizedMessage;
-      nsContentUtils::GetLocalizedString(
-        nsContentUtils::eLAYOUT_PROPERTIES,
-        "AnimationWarningWithGeometricProperties",
-        localizedMessage);
-      aPerformanceWarning = localizedMessage;
+      aPerformanceWarning =
+        AnimationPerformanceWarning::Type::WithGeometricProperties;
       return true;
     }
 
     // Check for unsupported transform animations
     if (property.mProperty == eCSSProperty_transform) {
       if (!CanAnimateTransformOnCompositor(aFrame,
                                            aPerformanceWarning)) {
         return true;
       }
     }
   }
 
   return false;
 }
 
 void
-KeyframeEffectReadOnly::SetPerformanceWarning(nsCSSProperty aProperty,
-                                              const nsAString &aMessage)
+KeyframeEffectReadOnly::SetPerformanceWarning(
+  nsCSSProperty aProperty,
+  const AnimationPerformanceWarning& aWarning)
 {
   for (AnimationProperty& property : mProperties) {
-    if (property.mProperty == aProperty) {
-      property.mPerformanceWarning.reset();
-      property.mPerformanceWarning.emplace(aMessage);
+    if (property.mProperty == aProperty &&
+        (!property.mPerformanceWarning ||
+         *property.mPerformanceWarning != aWarning)) {
+      property.mPerformanceWarning = Some(aWarning);
 
-      if (nsLayoutUtils::IsAnimationLoggingEnabled()) {
-        nsAutoCString logMessage = NS_ConvertUTF16toUTF8(aMessage);
+      nsXPIDLString localizedString;
+      if (nsLayoutUtils::IsAnimationLoggingEnabled() &&
+          property.mPerformanceWarning->ToLocalizedString(localizedString)) {
+        nsAutoCString logMessage = NS_ConvertUTF16toUTF8(localizedString);
         AnimationUtils::LogAsyncAnimationFailure(logMessage, mTarget);
       }
       return;
     }
   }
 }
 
 //---------------------------------------------------------------------
--- a/dom/animation/KeyframeEffect.h
+++ b/dom/animation/KeyframeEffect.h
@@ -6,16 +6,17 @@
 
 #ifndef mozilla_dom_KeyframeEffect_h
 #define mozilla_dom_KeyframeEffect_h
 
 #include "nsAutoPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIDocument.h"
 #include "nsWrapperCache.h"
+#include "mozilla/AnimationPerformanceWarning.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/ComputedTimingFunction.h" // ComputedTimingFunction
 #include "mozilla/LayerAnimationInfo.h"     // LayerAnimations::kRecords
 #include "mozilla/OwningNonNull.h"          // OwningNonNull<...>
 #include "mozilla/StickyTimeDuration.h"
 #include "mozilla/StyleAnimationValue.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/dom/AnimationEffectReadOnly.h"
@@ -141,19 +142,17 @@ struct AnimationProperty
   // between calling RequestRestyle on its EffectCompositor and when the
   // restyle is performed, this member may temporarily become false even if
   // the animation remains on the layer after the restyle.
   //
   // **NOTE**: This member is not included when comparing AnimationProperty
   // objects for equality.
   bool mIsRunningOnCompositor = false;
 
-  // A warning string indicating why this property could not be animated
-  // on the compositor.
-  Maybe<nsString> mPerformanceWarning;
+  Maybe<AnimationPerformanceWarning> mPerformanceWarning;
 
   InfallibleTArray<AnimationPropertySegment> mSegments;
 
   // NOTE: This operator does *not* compare the mWinsInCascade member *or* the
   // mIsRunningOnCompositor member.
   // This is because AnimationProperty objects are compared when recreating
   // CSS animations to determine if mutation observer change records need to
   // be created or not. However, at the point when these objects are compared
@@ -322,27 +321,30 @@ public:
   // when that is the case we simply disable all compositor animations
   // on the same element.
   //
   // Bug 1218620 - It seems like we don't need to be this restrictive. Wouldn't
   // it be ok to do 'opacity' animations on the compositor in either case?
   //
   // When returning true, |aOutPerformanceWarning| stores the reason why
   // we shouldn't run the compositor animations.
-  bool ShouldBlockCompositorAnimations(const nsIFrame* aFrame,
-                                       nsAString& aPerformanceWarning) const;
+  bool ShouldBlockCompositorAnimations(
+    const nsIFrame* aFrame,
+    AnimationPerformanceWarning::Type& aPerformanceWarning) const;
 
   nsIDocument* GetRenderedDocument() const;
   nsPresContext* GetPresContext() const;
 
-  // Associates a warning string with the animated property on the specified
-  // frame indicating why, for example, the property could not be animated
-  // on the compositor.
-  void SetPerformanceWarning(nsCSSProperty aProperty,
-                             const nsAString& aMessage);
+  // Associates a warning with the animated property on the specified frame
+  // indicating why, for example, the property could not be animated on the
+  // compositor. |aParams| and |aParamsLength| are optional parameters which
+  // will be used to generate a localized message for devtools.
+  void SetPerformanceWarning(
+    nsCSSProperty aProperty,
+    const AnimationPerformanceWarning& aWarning);
 
 protected:
   KeyframeEffectReadOnly(nsIDocument* aDocument,
                          Element* aTarget,
                          CSSPseudoElementType aPseudoType,
                          AnimationEffectTimingReadOnly* aTiming);
 
   virtual ~KeyframeEffectReadOnly();
@@ -397,18 +399,19 @@ private:
   nsIFrame* GetAnimationFrame() const;
 
   bool CanThrottle() const;
   bool CanThrottleTransformChanges(nsIFrame& aFrame) const;
 
   // Returns true unless Gecko limitations prevent performing transform
   // animations for |aFrame|. When returning true, the reason for the
   // limitation is stored in |aOutPerformanceWarning|.
-  static bool CanAnimateTransformOnCompositor(const nsIFrame* aFrame,
-                                              nsAString& aPerformanceWarning);
+  static bool CanAnimateTransformOnCompositor(
+    const nsIFrame* aFrame,
+    AnimationPerformanceWarning::Type& aPerformanceWarning);
   static bool IsGeometricProperty(const nsCSSProperty aProperty);
 
   static const TimeDuration OverflowRegionRefreshInterval();
 };
 
 class KeyframeEffect : public KeyframeEffectReadOnly
 {
 public:
--- a/dom/animation/moz.build
+++ b/dom/animation/moz.build
@@ -15,30 +15,32 @@ EXPORTS.mozilla.dom += [
     'AnimationTimeline.h',
     'CSSPseudoElement.h',
     'DocumentTimeline.h',
     'KeyframeEffect.h',
 ]
 
 EXPORTS.mozilla += [
     'AnimationComparator.h',
+    'AnimationPerformanceWarning.h',
     'AnimationUtils.h',
     'AnimValuesStyleRule.h',
     'ComputedTimingFunction.h',
     'EffectCompositor.h',
     'EffectSet.h',
     'PendingAnimationTracker.h',
     'PseudoElementHashEntry.h',
 ]
 
 UNIFIED_SOURCES += [
     'Animation.cpp',
     'AnimationEffectReadOnly.cpp',
     'AnimationEffectTiming.cpp',
     'AnimationEffectTimingReadOnly.cpp',
+    'AnimationPerformanceWarning.cpp',
     'AnimationTimeline.cpp',
     'AnimationUtils.cpp',
     'AnimValuesStyleRule.cpp',
     'ComputedTimingFunction.cpp',
     'CSSPseudoElement.cpp',
     'DocumentTimeline.cpp',
     'EffectCompositor.cpp',
     'EffectSet.cpp',
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -47,16 +47,17 @@
 #include "nsSVGElement.h"
 #include "nsSVGClipPathFrame.h"
 #include "GeckoProfiler.h"
 #include "nsViewManager.h"
 #include "ImageLayers.h"
 #include "ImageContainer.h"
 #include "nsCanvasFrame.h"
 #include "StickyScrollContainer.h"
+#include "mozilla/AnimationPerformanceWarning.h"
 #include "mozilla/AnimationUtils.h"
 #include "mozilla/EffectCompositor.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/LookAndFeel.h"
 #include "mozilla/PendingAnimationTracker.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/unused.h"
@@ -5583,24 +5584,20 @@ nsDisplayTransform::GetResultingTransfor
 
 bool
 nsDisplayOpacity::CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder)
 {
   if (ActiveLayerTracker::IsStyleAnimated(aBuilder, mFrame, eCSSProperty_opacity)) {
     return true;
   }
 
-  nsXPIDLString localizedMessage;
-  nsContentUtils::GetLocalizedString(
-    nsContentUtils::eLAYOUT_PROPERTIES,
-    "AnimationWarningOpacityFrameInactive",
-    localizedMessage);
-  EffectCompositor::SetPerformanceWarning(mFrame,
-                                          eCSSProperty_opacity,
-                                          localizedMessage);
+  EffectCompositor::SetPerformanceWarning(
+    mFrame, eCSSProperty_transform,
+    AnimationPerformanceWarning(
+      AnimationPerformanceWarning::Type::OpacityFrameInactive));
 
   return false;
 }
 
 bool
 nsDisplayTransform::ShouldPrerender(nsDisplayListBuilder* aBuilder) {
   if (!mMaybePrerender) {
     return false;
@@ -5638,24 +5635,21 @@ nsDisplayTransform::ShouldPrerenderTrans
 {
   // Elements whose transform has been modified recently, or which
   // have a compositor-animated transform, can be prerendered. An element
   // might have only just had its transform animated in which case
   // the ActiveLayerManager may not have been notified yet.
   if (!ActiveLayerTracker::IsStyleMaybeAnimated(aFrame, eCSSProperty_transform) &&
       !EffectCompositor::HasAnimationsForCompositor(aFrame,
                                                     eCSSProperty_transform)) {
-    nsXPIDLString localizedMessage;
-    nsContentUtils::GetLocalizedString(
-      nsContentUtils::eLAYOUT_PROPERTIES,
-      "AnimationWarningTransformFrameInactive",
-      localizedMessage);
-    EffectCompositor::SetPerformanceWarning(aFrame,
-                                            eCSSProperty_transform,
-                                            localizedMessage);
+    EffectCompositor::SetPerformanceWarning(
+      aFrame, eCSSProperty_transform,
+      AnimationPerformanceWarning(
+        AnimationPerformanceWarning::Type::TransformFrameInactive));
+
     return false;
   }
 
   nsSize refSize = aBuilder->RootReferenceFrame()->GetSize();
   // Only prerender if the transformed frame's size is <= the
   // reference frame size (~viewport), allowing a 1/8th fuzz factor
   // for shadows, borders, etc.
   refSize += nsSize(refSize.width / 8, refSize.height / 8);
@@ -5666,46 +5660,30 @@ nsDisplayTransform::ShouldPrerenderTrans
     nsRect visual = aFrame->GetVisualOverflowRect();
     if (visual.width <= maxInAppUnits && visual.height <= maxInAppUnits) {
       return true;
     }
   }
 
   nsRect visual = aFrame->GetVisualOverflowRect();
 
-  nsAutoString frameWidth, frameHeight,
-               refWidth, refHeight,
-               visualWidth, visualHeight,
-               maxInAppUnitsString;
-  frameWidth.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(frameSize.width));
-  frameHeight.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(frameSize.height));
-  refWidth.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(refSize.width));
-  refHeight.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(refSize.height));
-  visualWidth.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(visual.width));
-  visualHeight.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(visual.height));
-  maxInAppUnitsString.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(maxInAppUnits));
-
-  const char16_t* params[7]  = {
-    frameWidth.get(),
-    frameHeight.get(),
-    refWidth.get(),
-    refHeight.get(),
-    visualWidth.get(),
-    visualHeight.get(),
-    maxInAppUnitsString.get()
-  };
-
-  nsXPIDLString message;
-  nsContentUtils::FormatLocalizedString(nsContentUtils::eLAYOUT_PROPERTIES,
-                                        "AnimationWarningContentTooLarge",
-                                        params,
-                                        message);
-  EffectCompositor::SetPerformanceWarning(aFrame,
-                                          eCSSProperty_transform,
-                                          message);
+
+  EffectCompositor::SetPerformanceWarning(
+    aFrame, eCSSProperty_transform,
+    AnimationPerformanceWarning(
+      AnimationPerformanceWarning::Type::ContentTooLarge,
+      {
+        nsPresContext::AppUnitsToIntCSSPixels(frameSize.width),
+        nsPresContext::AppUnitsToIntCSSPixels(frameSize.height),
+        nsPresContext::AppUnitsToIntCSSPixels(refSize.width),
+        nsPresContext::AppUnitsToIntCSSPixels(refSize.height),
+        nsPresContext::AppUnitsToIntCSSPixels(visual.width),
+        nsPresContext::AppUnitsToIntCSSPixels(visual.height),
+        nsPresContext::AppUnitsToIntCSSPixels(maxInAppUnits)
+      }));
   return false;
 }
 
 /* If the matrix is singular, or a hidden backface is shown, the frame won't be visible or hit. */
 static bool IsFrameVisible(nsIFrame* aFrame, const Matrix4x4& aMatrix)
 {
   if (aMatrix.IsSingular()) {
     return false;