Backed out 5 changesets (bug 1554499) for frequent crashes, at least on OS X (bug 1594381). a=backout
authorSebastian Hengst <archaeopteryx@coole-files.de>
Wed, 06 Nov 2019 14:29:12 +0100
changeset 500868 d9daf28a5559712a8db772aa8388f444a93f4063
parent 500767 d73cfe3a04e90b5dff64f6d4e3c3a9183aec4ec5
child 500869 06c52ca1bdfcf4f1d3fce9b8b9ca94c757f065d6
push id99853
push userarchaeopteryx@coole-files.de
push dateWed, 06 Nov 2019 14:00:45 +0000
treeherderautoland@d6709b4ccf48 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout
bugs1554499, 1594381
milestone72.0a1
backs out3a49bec953389927936256a24c99bcde4ea13bd1
c802ab8cc73058de7f422c8f450d3f0cd9546df9
f60fee4844602e6978be09ab76761c9912369f6d
a49d1c9e8b143f666f1ff2268c6262b1294e7f00
133cddb65f59041b380e805668f515d711aeef0b
first release with
nightly linux32
d9daf28a5559 / 72.0a1 / 20191106132950 / files
nightly linux64
d9daf28a5559 / 72.0a1 / 20191106132950 / files
nightly mac
d9daf28a5559 / 72.0a1 / 20191106132950 / files
nightly win32
d9daf28a5559 / 72.0a1 / 20191106132950 / files
nightly win64
d9daf28a5559 / 72.0a1 / 20191106132950 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out 5 changesets (bug 1554499) for frequent crashes, at least on OS X (bug 1594381). a=backout Backed out changeset 3a49bec95338 (bug 1554499) Backed out changeset c802ab8cc730 (bug 1554499) Backed out changeset f60fee484460 (bug 1554499) Backed out changeset a49d1c9e8b14 (bug 1554499) Backed out changeset 133cddb65f59 (bug 1554499)
gfx/layers/wr/WebRenderCommandBuilder.h
gfx/layers/wr/WebRenderUserData.cpp
layout/generic/TextOverflow.cpp
layout/mathml/nsMathMLChar.cpp
layout/mathml/nsMathMLFrame.cpp
layout/mathml/nsMathMLmencloseFrame.cpp
layout/painting/nsDisplayList.cpp
layout/painting/nsDisplayList.h
layout/xul/nsBoxFrame.cpp
--- a/gfx/layers/wr/WebRenderCommandBuilder.h
+++ b/gfx/layers/wr/WebRenderCommandBuilder.h
@@ -187,27 +187,18 @@ class WebRenderCommandBuilder final {
     WebRenderUserDataTable* userDataTable =
         frame->GetProperty(WebRenderUserDataProperty::Key());
 
     if (!userDataTable) {
       userDataTable = new WebRenderUserDataTable();
       frame->AddProperty(WebRenderUserDataProperty::Key(), userDataTable);
     }
 
-    // TODO (miko): This is a slight hack. For OMTA, WebRenderAnimationData
-    // needs to be accessible with just (frame, display item type) -key,
-    // so a more specific per frame key cannot be used.
-    const uint32_t key =
-        T::Type() == WebRenderUserData::UserDataType::eAnimation
-            ? static_cast<uint32_t>(aItem->GetType())
-            : aItem->GetPerFrameKey();
-
-    RefPtr<WebRenderUserData>& data =
-        userDataTable->GetOrInsert(WebRenderUserDataKey(key, T::Type()));
-
+    RefPtr<WebRenderUserData>& data = userDataTable->GetOrInsert(
+        WebRenderUserDataKey(aItem->GetPerFrameKey(), T::Type()));
     if (!data) {
       data = new T(GetRenderRootStateManager(aRenderRoot), aItem);
       mWebRenderUserDatas.PutEntry(data);
       if (aOutIsRecycled) {
         *aOutIsRecycled = false;
       }
     }
 
--- a/gfx/layers/wr/WebRenderUserData.cpp
+++ b/gfx/layers/wr/WebRenderUserData.cpp
@@ -333,18 +333,17 @@ WebRenderImageData* WebRenderFallbackDat
   mImageData = MakeAndAddRef<WebRenderImageData>(mManager.get(),
                                                  mDisplayItemKey, mFrame);
 
   return mImageData.get();
 }
 
 WebRenderAnimationData::WebRenderAnimationData(RenderRootStateManager* aManager,
                                                nsDisplayItem* aItem)
-    : WebRenderUserData(aManager, static_cast<uint32_t>(aItem->GetType()),
-                        aItem->Frame()) {}
+    : WebRenderUserData(aManager, aItem) {}
 
 WebRenderAnimationData::~WebRenderAnimationData() {
   // It may be the case that nsDisplayItem that created this WebRenderUserData
   // gets destroyed without getting a chance to discard the compositor animation
   // id, so we should do it as part of cleanup here.
   uint64_t animationId = mAnimationInfo.GetCompositorAnimationsId();
   // animationId might be 0 if mAnimationInfo never held any active animations.
   if (animationId) {
--- a/layout/generic/TextOverflow.cpp
+++ b/layout/generic/TextOverflow.cpp
@@ -152,30 +152,20 @@ class nsDisplayTextOverflowMarker final 
  public:
   nsDisplayTextOverflowMarker(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                               const nsRect& aRect, nscoord aAscent,
                               const StyleTextOverflowSide& aStyle,
                               uint32_t aLineNumber, uint16_t aIndex)
       : nsPaintedDisplayItem(aBuilder, aFrame),
         mRect(aRect),
         mStyle(aStyle),
-        mAscent(aAscent) {
+        mAscent(aAscent),
+        mIndex((aLineNumber << 1) + aIndex) {
     MOZ_COUNT_CTOR(nsDisplayTextOverflowMarker);
   }
-
-  // Should have the same argument signature as the above ctor
-  static uint16_t CalculatePerFrameIndex(nsDisplayListBuilder* aBuilder,
-                                         nsIFrame* aFrame, const nsRect& aRect,
-                                         nscoord aAscent,
-                                         const StyleTextOverflowSide& aStyle,
-                                         uint32_t aLineNumber,
-                                         uint16_t aIndex) {
-    return (aLineNumber << 1) + aIndex;
-  }
-
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayTextOverflowMarker() {
     MOZ_COUNT_DTOR(nsDisplayTextOverflowMarker);
   }
 #endif
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
                            bool* aSnap) const override {
     *aSnap = false;
@@ -194,30 +184,33 @@ class nsDisplayTextOverflowMarker final 
       }
     }
     bool snap;
     return GetBounds(aBuilder, &snap);
   }
 
   virtual void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
 
+  virtual uint16_t CalculatePerFrameKey() const override { return mIndex; }
+
   void PaintTextToContext(gfxContext* aCtx, nsPoint aOffsetFromRect);
 
   virtual bool CreateWebRenderCommands(
       mozilla::wr::DisplayListBuilder& aBuilder,
       mozilla::wr::IpcResourceUpdateQueue& aResources,
       const StackingContextHelper& aSc,
       layers::RenderRootStateManager* aManager,
       nsDisplayListBuilder* aDisplayListBuilder) override;
 
   NS_DISPLAY_DECL_NAME("TextOverflow", TYPE_TEXT_OVERFLOW)
  private:
   nsRect mRect;  // in reference frame coordinates
   const StyleTextOverflowSide mStyle;
   nscoord mAscent;  // baseline for the marker text in mRect
+  uint16_t mIndex;
 };
 
 static void PaintTextShadowCallback(gfxContext* aCtx, nsPoint aShadowOffset,
                                     const nscolor& aShadowColor, void* aData) {
   reinterpret_cast<nsDisplayTextOverflowMarker*>(aData)->PaintTextToContext(
       aCtx, aShadowOffset);
 }
 
--- a/layout/mathml/nsMathMLChar.cpp
+++ b/layout/mathml/nsMathMLChar.cpp
@@ -1715,27 +1715,20 @@ void nsDisplayMathMLSelectionRect::Paint
 
 class nsDisplayMathMLCharForeground final : public nsPaintedDisplayItem {
  public:
   nsDisplayMathMLCharForeground(nsDisplayListBuilder* aBuilder,
                                 nsIFrame* aFrame, nsMathMLChar* aChar,
                                 uint16_t aIndex, bool aIsSelected)
       : nsPaintedDisplayItem(aBuilder, aFrame),
         mChar(aChar),
+        mIndex(aIndex),
         mIsSelected(aIsSelected) {
     MOZ_COUNT_CTOR(nsDisplayMathMLCharForeground);
   }
-
-  // Should have the same argument signature as the above ctor
-  static uint16_t CalculatePerFrameIndex(nsDisplayListBuilder* aBuilder,
-                                         nsIFrame* aFrame, nsMathMLChar* aChar,
-                                         uint16_t aIndex, bool aIsSelected) {
-    return aIndex;
-  }
-
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayMathMLCharForeground() {
     MOZ_COUNT_DTOR(nsDisplayMathMLCharForeground);
   }
 #endif
 
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
                            bool* aSnap) const override {
@@ -1760,18 +1753,21 @@ class nsDisplayMathMLCharForeground fina
   NS_DISPLAY_DECL_NAME("MathMLCharForeground", TYPE_MATHML_CHAR_FOREGROUND)
 
   virtual nsRect GetComponentAlphaBounds(
       nsDisplayListBuilder* aBuilder) const override {
     bool snap;
     return GetBounds(aBuilder, &snap);
   }
 
+  virtual uint16_t CalculatePerFrameKey() const override { return mIndex; }
+
  private:
   nsMathMLChar* mChar;
+  uint16_t mIndex;
   bool mIsSelected;
 };
 
 #ifdef DEBUG
 class nsDisplayMathMLCharDebug final : public nsPaintedDisplayItem {
  public:
   nsDisplayMathMLCharDebug(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                            const nsRect& aRect)
--- a/layout/mathml/nsMathMLFrame.cpp
+++ b/layout/mathml/nsMathMLFrame.cpp
@@ -299,35 +299,30 @@ void nsMathMLFrame::DisplayBoundingMetri
       aBuilder, aFrame, nsRect(x, y, w, h));
 }
 #endif
 
 class nsDisplayMathMLBar final : public nsPaintedDisplayItem {
  public:
   nsDisplayMathMLBar(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                      const nsRect& aRect, uint16_t aIndex)
-      : nsPaintedDisplayItem(aBuilder, aFrame), mRect(aRect) {
+      : nsPaintedDisplayItem(aBuilder, aFrame), mRect(aRect), mIndex(aIndex) {
     MOZ_COUNT_CTOR(nsDisplayMathMLBar);
   }
-
-  // Should have the same argument signature as the above ctor
-  static uint16_t CalculatePerFrameIndex(nsDisplayListBuilder* aBuilder,
-                                         nsIFrame* aFrame, const nsRect& aRect,
-                                         uint16_t aIndex) {
-    return aIndex;
-  }
-
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayMathMLBar() { MOZ_COUNT_DTOR(nsDisplayMathMLBar); }
 #endif
 
+  virtual uint16_t CalculatePerFrameKey() const override { return mIndex; }
+
   virtual void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
   NS_DISPLAY_DECL_NAME("MathMLBar", TYPE_MATHML_BAR)
  private:
   nsRect mRect;
+  uint16_t mIndex;
 };
 
 void nsDisplayMathMLBar::Paint(nsDisplayListBuilder* aBuilder,
                                gfxContext* aCtx) {
   // paint the bar with the current text color
   DrawTarget* drawTarget = aCtx->GetDrawTarget();
   Rect rect = NSRectToNonEmptySnappedRect(
       mRect + ToReferenceFrame(), mFrame->PresContext()->AppUnitsPerDevPixel(),
--- a/layout/mathml/nsMathMLmencloseFrame.cpp
+++ b/layout/mathml/nsMathMLmencloseFrame.cpp
@@ -712,29 +712,22 @@ class nsDisplayNotation final : public n
                     const nsRect& aRect, nscoord aThickness,
                     nsMencloseNotation aType)
       : nsPaintedDisplayItem(aBuilder, aFrame),
         mRect(aRect),
         mThickness(aThickness),
         mType(aType) {
     MOZ_COUNT_CTOR(nsDisplayNotation);
   }
-
-  // Should have the same argument signature as the above ctor
-  static uint16_t CalculatePerFrameIndex(nsDisplayListBuilder* aBuilder,
-                                         nsIFrame* aFrame, const nsRect& aRect,
-                                         nscoord aThickness,
-                                         nsMencloseNotation aType) {
-    return aType;
-  }
-
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayNotation() { MOZ_COUNT_DTOR(nsDisplayNotation); }
 #endif
 
+  virtual uint16_t CalculatePerFrameKey() const override { return mType; }
+
   virtual void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
   NS_DISPLAY_DECL_NAME("MathMLMencloseNotation", TYPE_MATHML_MENCLOSE_NOTATION)
 
  private:
   nsRect mRect;
   nscoord mThickness;
   nsMencloseNotation mType;
 };
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -4107,23 +4107,16 @@ nsDisplayBackgroundImage::nsDisplayBackg
     // asynchronously.
     if (Maybe<nsRect> viewportRect = GetViewportRectRelativeToReferenceFrame(
             aInitData.builder, mFrame)) {
       SetBuildingRect(mBounds.Intersect(*viewportRect));
     }
   }
 }
 
-// Should have an identical argument signature to the above ctor
-uint16_t nsDisplayBackgroundImage::CalculatePerFrameIndex(
-    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, const InitData& aInitData,
-    nsIFrame* aFrameForBounds) {
-  return aInitData.layer;
-}
-
 nsDisplayBackgroundImage::~nsDisplayBackgroundImage() {
 #ifdef NS_BUILD_REFCNT_LOGGING
   MOZ_COUNT_DTOR(nsDisplayBackgroundImage);
 #endif
   if (mDependentFrame) {
     mDependentFrame->RemoveDisplayItem(this);
   }
 }
@@ -4917,30 +4910,23 @@ nsRect nsDisplayBackgroundImage::GetBoun
       presContext, frame, mBackgroundRect, clipRect, layer,
       aBuilder->GetBackgroundPaintFlags());
 }
 
 nsDisplayTableBackgroundImage::nsDisplayTableBackgroundImage(
     nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, const InitData& aData,
     nsIFrame* aCellFrame)
     : nsDisplayBackgroundImage(aBuilder, aFrame, aData, aCellFrame),
-      mStyleFrame(aCellFrame) {
+      mStyleFrame(aCellFrame),
+      mTableType(GetTableTypeFromFrame(mStyleFrame)) {
   if (aBuilder->IsRetainingDisplayList()) {
     mStyleFrame->AddDisplayItem(this);
   }
 }
 
-// Should have an identical argument signature to the above ctor
-uint16_t nsDisplayTableBackgroundImage::CalculatePerFrameIndex(
-    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, const InitData& aData,
-    nsIFrame* aCellFrame) {
-  return CalculateTablePerFrameKey(aData.layer,
-                                   GetTableTypeFromFrame(aCellFrame));
-}
-
 nsDisplayTableBackgroundImage::~nsDisplayTableBackgroundImage() {
   if (mStyleFrame) {
     mStyleFrame->RemoveDisplayItem(this);
   }
 }
 
 bool nsDisplayTableBackgroundImage::IsInvalid(nsRect& aRect) const {
   bool result = mStyleFrame ? mStyleFrame->IsInvalid(aRect) : false;
@@ -5523,56 +5509,43 @@ bool nsDisplayEventReceiver::CreateWebRe
   return true;
 }
 
 nsDisplayCompositorHitTestInfo::nsDisplayCompositorHitTestInfo(
     nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
     const mozilla::gfx::CompositorHitTestInfo& aHitTestFlags, uint16_t aIndex,
     const mozilla::Maybe<nsRect>& aArea)
     : nsDisplayHitTestInfoItem(aBuilder, aFrame),
+      mIndex(aIndex),
       mAppUnitsPerDevPixel(mFrame->PresContext()->AppUnitsPerDevPixel()) {
   MOZ_COUNT_CTOR(nsDisplayCompositorHitTestInfo);
   // We should never even create this display item if we're not building
   // compositor hit-test info or if the computed hit info indicated the
   // frame is invisible to hit-testing
   MOZ_ASSERT(aBuilder->BuildCompositorHitTestInfo());
   MOZ_ASSERT(aHitTestFlags != CompositorHitTestInvisibleToHit);
 
   const nsRect& area =
       aArea.isSome() ? *aArea : aFrame->GetCompositorHitTestArea(aBuilder);
 
   SetHitTestInfo(area, aHitTestFlags);
   InitializeScrollTarget(aBuilder);
 }
 
-// Should have the same argument signature as the above ctor
-uint16_t nsDisplayCompositorHitTestInfo::CalculatePerFrameIndex(
-    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
-    const mozilla::gfx::CompositorHitTestInfo& aHitTestFlags, uint16_t aIndex,
-    const mozilla::Maybe<nsRect>& aArea) {
-  return aIndex;
-}
-
 nsDisplayCompositorHitTestInfo::nsDisplayCompositorHitTestInfo(
     nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
     mozilla::UniquePtr<HitTestInfo>&& aHitTestInfo)
     : nsDisplayHitTestInfoItem(aBuilder, aFrame),
+      mIndex(0),
       mAppUnitsPerDevPixel(mFrame->PresContext()->AppUnitsPerDevPixel()) {
   MOZ_COUNT_CTOR(nsDisplayCompositorHitTestInfo);
   SetHitTestInfo(std::move(aHitTestInfo));
   InitializeScrollTarget(aBuilder);
 }
 
-// Should have the same argument signature as the above ctor
-uint16_t nsDisplayCompositorHitTestInfo::CalculatePerFrameIndex(
-    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
-    mozilla::UniquePtr<HitTestInfo>&& aHitTestInfo) {
-  return 0;
-}
-
 void nsDisplayCompositorHitTestInfo::InitializeScrollTarget(
     nsDisplayListBuilder* aBuilder) {
   if (aBuilder->GetCurrentScrollbarDirection().isSome()) {
     // In the case of scrollbar frames, we use the scrollbar's target
     // scrollframe instead of the scrollframe with which the scrollbar actually
     // moves.
     MOZ_ASSERT(HitTestFlags().contains(CompositorHitTestFlags::eScrollbar));
     mScrollTarget = mozilla::Some(aBuilder->GetCurrentScrollbarTarget());
@@ -5617,16 +5590,20 @@ bool nsDisplayCompositorHitTestInfo::Cre
   const wr::LayoutRect rect = wr::ToLayoutRect(devRect);
 
   aBuilder.PushHitTest(rect, rect, !BackfaceIsHidden());
   aBuilder.ClearHitTestInfo();
 
   return true;
 }
 
+uint16_t nsDisplayCompositorHitTestInfo::CalculatePerFrameKey() const {
+  return mIndex;
+}
+
 int32_t nsDisplayCompositorHitTestInfo::ZIndex() const {
   return mOverrideZIndex ? *mOverrideZIndex
                          : nsDisplayHitTestInfoItem::ZIndex();
 }
 
 void nsDisplayCompositorHitTestInfo::SetOverrideZIndex(int32_t aZIndex) {
   mOverrideZIndex = Some(aZIndex);
 }
@@ -6154,16 +6131,17 @@ nsDisplayWrapList::nsDisplayWrapList(nsD
 
 nsDisplayWrapList::nsDisplayWrapList(
     nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
     const ActiveScrolledRoot* aActiveScrolledRoot, bool aClearClipChain,
     uint16_t aIndex)
     : nsDisplayHitTestInfoItem(aBuilder, aFrame, aActiveScrolledRoot),
       mFrameActiveScrolledRoot(aBuilder->CurrentActiveScrolledRoot()),
       mOverrideZIndex(0),
+      mIndex(aIndex),
       mHasZIndexOverride(false),
       mClearingClipChain(aClearClipChain) {
   MOZ_COUNT_CTOR(nsDisplayWrapList);
 
   mBaseBuildingRect = GetBuildingRect();
 
   mListPtr = &mList;
   mListPtr->AppendToTop(aList);
@@ -6197,16 +6175,17 @@ nsDisplayWrapList::nsDisplayWrapList(
   SetBuildingRect(visible);
 }
 
 nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
                                      nsIFrame* aFrame, nsDisplayItem* aItem)
     : nsDisplayHitTestInfoItem(aBuilder, aFrame,
                                aBuilder->CurrentActiveScrolledRoot()),
       mOverrideZIndex(0),
+      mIndex(0),
       mHasZIndexOverride(false) {
   MOZ_COUNT_CTOR(nsDisplayWrapList);
 
   mBaseBuildingRect = GetBuildingRect();
 
   mListPtr = &mList;
   mListPtr->AppendToTop(aItem);
   nsDisplayWrapList::UpdateBounds(aBuilder);
@@ -6754,17 +6733,17 @@ bool nsDisplayOpacity::CreateWebRenderCo
 }
 
 nsDisplayBlendMode::nsDisplayBlendMode(
     nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
     uint8_t aBlendMode, const ActiveScrolledRoot* aActiveScrolledRoot,
     uint16_t aIndex)
     : nsDisplayWrapList(aBuilder, aFrame, aList, aActiveScrolledRoot, true),
       mBlendMode(aBlendMode),
-      mIsBackgroundBlendMode(aIndex != 0) {
+      mIndex(aIndex) {
   MOZ_COUNT_CTOR(nsDisplayBlendMode);
 }
 
 nsRegion nsDisplayBlendMode::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
                                              bool* aSnap) const {
   *aSnap = false;
   // We are never considered opaque
   return nsRegion();
@@ -6836,17 +6815,17 @@ bool nsDisplayBlendMode::CanMerge(const 
   if (!HasDifferentFrame(aItem) || !HasSameTypeAndClip(aItem) ||
       !HasSameContent(aItem)) {
     return false;
   }
 
   const nsDisplayBlendMode* item =
       static_cast<const nsDisplayBlendMode*>(aItem);
 
-  if (item->mIsBackgroundBlendMode || mIsBackgroundBlendMode) {
+  if (item->mIndex != 0 || mIndex != 0) {
     // Don't merge background-blend-mode items
     return false;
   }
 
   return true;
 }
 
 /* static */
@@ -6930,17 +6909,18 @@ nsDisplayOwnLayer::nsDisplayOwnLayer(
     const ActiveScrolledRoot* aActiveScrolledRoot,
     nsDisplayOwnLayerFlags aFlags, const ScrollbarData& aScrollbarData,
     bool aForceActive, bool aClearClipChain, uint16_t aIndex)
     : nsDisplayWrapList(aBuilder, aFrame, aList, aActiveScrolledRoot,
                         aClearClipChain),
       mFlags(aFlags),
       mScrollbarData(aScrollbarData),
       mForceActive(aForceActive),
-      mWrAnimationId(0) {
+      mWrAnimationId(0),
+      mIndex(aIndex) {
   MOZ_COUNT_CTOR(nsDisplayOwnLayer);
 
   // For scroll thumb layers, override the AGR to be the thumb's AGR rather
   // than the AGR for mFrame (which is the slider frame).
   if (IsScrollThumbLayer()) {
     if (nsIFrame* thumbFrame = nsBox::GetChildXULBox(mFrame)) {
       mAnimatedGeometryRoot = aBuilder->FindAnimatedGeometryRootFor(thumbFrame);
     }
@@ -7390,28 +7370,30 @@ already_AddRefed<Layer> nsDisplayResolut
 }
 
 nsDisplayFixedPosition::nsDisplayFixedPosition(
     nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
     const ActiveScrolledRoot* aActiveScrolledRoot,
     const ActiveScrolledRoot* aContainerASR)
     : nsDisplayOwnLayer(aBuilder, aFrame, aList, aActiveScrolledRoot),
       mContainerASR(aContainerASR),
+      mIndex(0),
       mIsFixedBackground(false) {
   MOZ_COUNT_CTOR(nsDisplayFixedPosition);
   Init(aBuilder);
 }
 
 nsDisplayFixedPosition::nsDisplayFixedPosition(nsDisplayListBuilder* aBuilder,
                                                nsIFrame* aFrame,
                                                nsDisplayList* aList,
                                                uint16_t aIndex)
     : nsDisplayOwnLayer(aBuilder, aFrame, aList,
                         aBuilder->CurrentActiveScrolledRoot()),
       mContainerASR(nullptr),  // XXX maybe this should be something?
+      mIndex(aIndex),
       mIsFixedBackground(true) {
   MOZ_COUNT_CTOR(nsDisplayFixedPosition);
   Init(aBuilder);
 }
 
 void nsDisplayFixedPosition::Init(nsDisplayListBuilder* aBuilder) {
   mAnimatedGeometryRootForScrollMetadata = mAnimatedGeometryRoot;
   if (ShouldFixToViewport(aBuilder)) {
@@ -7537,17 +7519,18 @@ TableType GetTableTypeFromFrame(nsIFrame
   MOZ_ASSERT_UNREACHABLE("Invalid frame.");
   return TableType::Table;
 }
 
 nsDisplayTableFixedPosition::nsDisplayTableFixedPosition(
     nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
     uint16_t aIndex, nsIFrame* aAncestorFrame)
     : nsDisplayFixedPosition(aBuilder, aFrame, aList, aIndex),
-      mAncestorFrame(aAncestorFrame) {
+      mAncestorFrame(aAncestorFrame),
+      mTableType(GetTableTypeFromFrame(aAncestorFrame)) {
   if (aBuilder->IsRetainingDisplayList()) {
     mAncestorFrame->AddDisplayItem(this);
   }
 }
 
 /* static */
 nsDisplayTableFixedPosition*
 nsDisplayTableFixedPosition::CreateForFixedBackground(
@@ -8019,16 +8002,17 @@ nsDisplayTransform::nsDisplayTransform(n
                                        const nsRect& aChildrenBuildingRect,
                                        uint16_t aIndex)
     : nsDisplayHitTestInfoItem(aBuilder, aFrame),
       mTransform(Some(Matrix4x4())),
       mTransformGetter(nullptr),
       mAnimatedGeometryRootForChildren(mAnimatedGeometryRoot),
       mAnimatedGeometryRootForScrollMetadata(mAnimatedGeometryRoot),
       mChildrenBuildingRect(aChildrenBuildingRect),
+      mIndex(aIndex),
       mIsTransformSeparator(true),
       mAllowAsyncAnimation(false) {
   MOZ_COUNT_CTOR(nsDisplayTransform);
   MOZ_ASSERT(aFrame, "Must have a frame!");
   Init(aBuilder, aList);
 }
 
 nsDisplayTransform::nsDisplayTransform(nsDisplayListBuilder* aBuilder,
@@ -8036,16 +8020,17 @@ nsDisplayTransform::nsDisplayTransform(n
                                        const nsRect& aChildrenBuildingRect,
                                        uint16_t aIndex,
                                        bool aAllowAsyncAnimation)
     : nsDisplayHitTestInfoItem(aBuilder, aFrame),
       mTransformGetter(nullptr),
       mAnimatedGeometryRootForChildren(mAnimatedGeometryRoot),
       mAnimatedGeometryRootForScrollMetadata(mAnimatedGeometryRoot),
       mChildrenBuildingRect(aChildrenBuildingRect),
+      mIndex(aIndex),
       mIsTransformSeparator(false),
       mAllowAsyncAnimation(aAllowAsyncAnimation) {
   MOZ_COUNT_CTOR(nsDisplayTransform);
   MOZ_ASSERT(aFrame, "Must have a frame!");
   SetReferenceFrameToAncestor(aBuilder);
   Init(aBuilder, aList);
 }
 
@@ -8053,16 +8038,17 @@ nsDisplayTransform::nsDisplayTransform(
     nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
     const nsRect& aChildrenBuildingRect, uint16_t aIndex,
     ComputeTransformFunction aTransformGetter)
     : nsDisplayHitTestInfoItem(aBuilder, aFrame),
       mTransformGetter(aTransformGetter),
       mAnimatedGeometryRootForChildren(mAnimatedGeometryRoot),
       mAnimatedGeometryRootForScrollMetadata(mAnimatedGeometryRoot),
       mChildrenBuildingRect(aChildrenBuildingRect),
+      mIndex(aIndex),
       mIsTransformSeparator(false),
       mAllowAsyncAnimation(false) {
   MOZ_COUNT_CTOR(nsDisplayTransform);
   MOZ_ASSERT(aFrame, "Must have a frame!");
   Init(aBuilder, aList);
 }
 
 void nsDisplayTransform::SetReferenceFrameToAncestor(
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -2065,20 +2065,19 @@ class RetainedDisplayList;
   friend T* MakeClone(nsDisplayListBuilder* aBuilder, const T* aItem);      \
                                                                             \
   nsDisplayWrapList* Clone(nsDisplayListBuilder* aBuilder) const override { \
     return MakeClone(aBuilder, this);                                       \
   }
 
 template <typename T>
 MOZ_ALWAYS_INLINE T* MakeClone(nsDisplayListBuilder* aBuilder, const T* aItem) {
-  uint16_t key = aItem->GetPerFrameIndex();
   T* item = new (aBuilder) T(aBuilder, *aItem);
   item->SetType(T::ItemType());
-  item->SetPerFrameIndex(key);
+  item->SetPerFrameKey(item->CalculatePerFrameKey());
   return item;
 }
 
 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
 void AssertUniqueItem(nsDisplayItem* aItem);
 #endif
 
 /**
@@ -2099,25 +2098,23 @@ MOZ_ALWAYS_INLINE T* MakeDisplayItem(nsD
 
   const DisplayItemType type = T::ItemType();
   if (aBuilder->InEventsAndPluginsOnly() &&
       !ShouldBuildItemForEventsOrPlugins(type)) {
     // This item is not needed for events or plugins.
     return nullptr;
   }
 
-  uint16_t key =
-      T::CalculatePerFrameIndex(aBuilder, aFrame, std::forward<Args>(aArgs)...);
   T* item = new (aBuilder) T(aBuilder, aFrame, std::forward<Args>(aArgs)...);
 
   if (type != DisplayItemType::TYPE_GENERIC) {
     item->SetType(type);
   }
 
-  item->SetPerFrameIndex(key);
+  item->SetPerFrameKey(item->CalculatePerFrameKey());
   item->SetExtraPageForPageNum(aBuilder->GetBuildingExtraPagesForPageNum());
 
   nsPaintedDisplayItem* paintedItem = item->AsPaintedDisplayItem();
   if (paintedItem) {
     UpdateDisplayItemData(paintedItem);
   }
 
   if (aBuilder->InInvalidSubtree() ||
@@ -2274,35 +2271,19 @@ class nsDisplayItemBase : public nsDispl
     // The low 8 bits are the display item type.
     return (static_cast<uint32_t>(mExtraPageForPageNum)
             << (TYPE_BITS + (sizeof(mKey) * 8))) |
            (static_cast<uint32_t>(mKey) << TYPE_BITS) |
            static_cast<uint32_t>(mType);
   }
 
   /**
-   * Gets the core component of the PerFrameKey without mixing it.
-   * (This is only used by MakeClone, everyone else should use GetPerFrameKey.)
-   */
-  uint16_t GetPerFrameIndex() const { return mKey; }
-
-  /**
-   * Returns the per-frame-key that this display item wants to have for the
-   * given constructor arguments. If the display item doesn't provide an impl of
-   * CalculatePerFrameIndex, then this implementation that just returns 0 will
-   * be used.
-   *
-   * This is computed independently of the actual ctor so that we can identify
-   * if we've already allocated an instance of this display item which we can
-   * reuse. (not yet implemented)
-   */
-  template <typename... Args>
-  static uint16_t CalculatePerFrameIndex(Args&&... aArgs) {
-    return 0;
-  }
+   * Returns the initial per frame key for this display item.
+   */
+  virtual uint16_t CalculatePerFrameKey() const { return 0; }
 
   /**
    * Returns true if this item was reused during display list merging.
    */
   bool IsReused() const {
     return mItemFlags.contains(ItemBaseFlag::ReusedItem);
   }
 
@@ -2405,17 +2386,17 @@ class nsDisplayItemBase : public nsDispl
   virtual ~nsDisplayItemBase() {
     MOZ_COUNT_DTOR(nsDisplayItemBase);
     if (mFrame) {
       mFrame->RemoveDisplayItem(this);
     }
   }
 
   void SetType(const DisplayItemType aType) { mType = aType; }
-  void SetPerFrameIndex(const uint16_t aKey) { mKey = aKey; }
+  void SetPerFrameKey(const uint16_t aKey) { mKey = aKey; }
 
   // Display list building for printing can build duplicate
   // container display items when they contain a mixture of
   // OOF and normal content that is spread across multiple
   // pages. We include the page number for the duplicates
   // to make our GetPerFrameKey unique.
   void SetExtraPageForPageNum(const uint8_t aPageNum) {
     mExtraPageForPageNum = aPageNum;
@@ -4399,40 +4380,27 @@ class nsDisplaySolidColorBase : public n
   nscolor mColor;
 };
 
 class nsDisplaySolidColor : public nsDisplaySolidColorBase {
  public:
   nsDisplaySolidColor(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                       const nsRect& aBounds, nscolor aColor,
                       uint16_t aIndex = 0, bool aCanBeReused = true)
-      : nsDisplaySolidColorBase(aBuilder, aFrame, aColor), mBounds(aBounds) {
+      : nsDisplaySolidColorBase(aBuilder, aFrame, aColor),
+        mBounds(aBounds),
+        mIndex(aIndex) {
     NS_ASSERTION(NS_GET_A(aColor) > 0,
                  "Don't create invisible nsDisplaySolidColors!");
     MOZ_COUNT_CTOR(nsDisplaySolidColor);
     if (!aCanBeReused) {
       SetCantBeReused();
     }
   }
 
-  /**
-   * If we have multiple SolidColor items in a single frame's
-   * display list, aIndex should be used as their unique
-   * identifier. Note this mapping remains stable even if the
-   * dirty rect changes.
-   */
-  // Should have an identical argument signature to the above ctor
-  static uint16_t CalculatePerFrameIndex(nsDisplayListBuilder* aBuilder,
-                                         nsIFrame* aFrame,
-                                         const nsRect& aBounds, nscolor aColor,
-                                         uint16_t aIndex = 0,
-                                         bool aCanBeReused = true) {
-    return aIndex;
-  }
-
 #ifdef NS_BUILD_REFCNT_LOGGING
   ~nsDisplaySolidColor() override { MOZ_COUNT_DTOR(nsDisplaySolidColor); }
 #endif
 
   NS_DISPLAY_DECL_NAME("SolidColor", TYPE_SOLID_COLOR)
 
   nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
   LayerState GetLayerState(
@@ -4455,20 +4423,28 @@ class nsDisplaySolidColor : public nsDis
       return mOverrideZIndex.value();
     }
     return nsDisplaySolidColorBase::ZIndex();
   }
 
   void SetOverrideZIndex(int32_t aZIndex) {
     mOverrideZIndex = mozilla::Some(aZIndex);
   }
+  /**
+   * If we have multiple SolidColor items in a single frame's
+   * display list, mIndex should be used as their unique
+   * identifier. Note this mapping remains stable even if the
+   * dirty rect changes.
+   */
+  uint16_t CalculatePerFrameKey() const override { return mIndex; }
 
  private:
   nsRect mBounds;
   mozilla::Maybe<int32_t> mOverrideZIndex;
+  const uint16_t mIndex;
 };
 
 /**
  * A display item that renders a solid color over a region. This is not
  * exposed through CSS, its only purpose is efficient invalidation of
  * the find bar highlighter dimmer.
  */
 class nsDisplaySolidColorRegion : public nsPaintedDisplayItem {
@@ -4557,23 +4533,16 @@ class nsDisplayBackgroundImage : public 
    */
   static InitData GetInitData(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                               uint16_t aLayer, const nsRect& aBackgroundRect,
                               mozilla::ComputedStyle* aBackgroundStyle);
 
   explicit nsDisplayBackgroundImage(nsDisplayListBuilder* aBuilder,
                                     nsIFrame* aFrame, const InitData& aInitData,
                                     nsIFrame* aFrameForBounds = nullptr);
-
-  // Should have an identical argument signature to the above ctor
-  static uint16_t CalculatePerFrameIndex(nsDisplayListBuilder* aBuilder,
-                                         nsIFrame* aFrame,
-                                         const InitData& aInitData,
-                                         nsIFrame* aFrameForBounds = nullptr);
-
   ~nsDisplayBackgroundImage() override;
 
   NS_DISPLAY_DECL_NAME("Background", TYPE_BACKGROUND)
 
   // This will create and append new items for all the layers of the
   // background. Returns whether we appended a themed background.
   // aAllowWillPaintBorderOptimization should usually be left at true, unless
   // aFrame has special border drawing that causes opaque borders to not
@@ -4611,16 +4580,18 @@ class nsDisplayBackgroundImage : public 
 
   /**
    * GetBounds() returns the background painting area.
    */
   nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
 
   void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
 
+  uint16_t CalculatePerFrameKey() const override { return mLayer; }
+
   /**
    * Return the background positioning area.
    * (GetBounds() returns the background painting area.)
    * Can be called only when mBackgroundStyle is non-null.
    */
   nsRect GetPositioningArea() const;
 
   /**
@@ -4755,43 +4726,41 @@ static uint16_t CalculateTablePerFrameKe
  *
  * Also store ancestor frame as mStyleFrame for all rendering informations.
  */
 class nsDisplayTableBackgroundImage : public nsDisplayBackgroundImage {
  public:
   nsDisplayTableBackgroundImage(nsDisplayListBuilder* aBuilder,
                                 nsIFrame* aFrame, const InitData& aInitData,
                                 nsIFrame* aCellFrame);
-
-  // Should have an identical argument signature to the above ctor
-  static uint16_t CalculatePerFrameIndex(nsDisplayListBuilder* aBuilder,
-                                         nsIFrame* aFrame,
-                                         const InitData& aInitData,
-                                         nsIFrame* aCellFrame);
-
   ~nsDisplayTableBackgroundImage() override;
 
   NS_DISPLAY_DECL_NAME("TableBackgroundImage", TYPE_TABLE_BACKGROUND_IMAGE)
 
+  uint16_t CalculatePerFrameKey() const override {
+    return CalculateTablePerFrameKey(mLayer, mTableType);
+  }
+
   bool IsInvalid(nsRect& aRect) const override;
 
   nsIFrame* FrameForInvalidation() const override { return mStyleFrame; }
 
   void RemoveFrame(nsIFrame* aFrame) override {
     if (aFrame == mStyleFrame) {
       mStyleFrame = nullptr;
       SetDeletedFrame();
     }
     nsDisplayBackgroundImage::RemoveFrame(aFrame);
   }
 
  protected:
   nsIFrame* StyleFrame() const override { return mStyleFrame; }
 
   nsIFrame* mStyleFrame;
+  TableType mTableType;
 };
 
 /**
  * A display item to paint the native theme background for a frame.
  */
 class nsDisplayThemedBackground : public nsPaintedDisplayItem {
  public:
   nsDisplayThemedBackground(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
@@ -4874,52 +4843,50 @@ class nsDisplayThemedBackground : public
 
 class nsDisplayTableThemedBackground : public nsDisplayThemedBackground {
  public:
   nsDisplayTableThemedBackground(nsDisplayListBuilder* aBuilder,
                                  nsIFrame* aFrame,
                                  const nsRect& aBackgroundRect,
                                  nsIFrame* aAncestorFrame)
       : nsDisplayThemedBackground(aBuilder, aFrame, aBackgroundRect),
-        mAncestorFrame(aAncestorFrame) {
+        mAncestorFrame(aAncestorFrame),
+        mTableType(GetTableTypeFromFrame(aAncestorFrame)) {
     if (aBuilder->IsRetainingDisplayList()) {
       mAncestorFrame->AddDisplayItem(this);
     }
   }
 
-  // Should have an identical argument signature to the above ctor
-  static uint16_t CalculatePerFrameIndex(nsDisplayListBuilder* aBuilder,
-                                         nsIFrame* aFrame,
-                                         const nsRect& aBackgroundRect,
-                                         nsIFrame* aAncestorFrame) {
-    return static_cast<uint8_t>(GetTableTypeFromFrame(aAncestorFrame));
-  }
-
   ~nsDisplayTableThemedBackground() override {
     if (mAncestorFrame) {
       mAncestorFrame->RemoveDisplayItem(this);
     }
   }
 
   NS_DISPLAY_DECL_NAME("TableThemedBackground",
                        TYPE_TABLE_THEMED_BACKGROUND_IMAGE)
 
+  uint16_t CalculatePerFrameKey() const override {
+    return static_cast<uint8_t>(mTableType);
+  }
+
   nsIFrame* FrameForInvalidation() const override { return mAncestorFrame; }
 
   void RemoveFrame(nsIFrame* aFrame) override {
     if (aFrame == mAncestorFrame) {
       mAncestorFrame = nullptr;
       SetDeletedFrame();
     }
     nsDisplayThemedBackground::RemoveFrame(aFrame);
   }
 
  protected:
   nsIFrame* StyleFrame() const override { return mAncestorFrame; }
   nsIFrame* mAncestorFrame;
+  TableType mTableType;
 };
 
 class nsDisplayBackgroundColor : public nsPaintedDisplayItem {
   typedef mozilla::gfx::Color Color;
 
  public:
   nsDisplayBackgroundColor(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                            const nsRect& aBackgroundRect,
@@ -5059,31 +5026,23 @@ class nsDisplayBackgroundColor : public 
 class nsDisplayTableBackgroundColor : public nsDisplayBackgroundColor {
  public:
   nsDisplayTableBackgroundColor(nsDisplayListBuilder* aBuilder,
                                 nsIFrame* aFrame, const nsRect& aBackgroundRect,
                                 const mozilla::ComputedStyle* aBackgroundStyle,
                                 const nscolor& aColor, nsIFrame* aAncestorFrame)
       : nsDisplayBackgroundColor(aBuilder, aFrame, aBackgroundRect,
                                  aBackgroundStyle, aColor),
-        mAncestorFrame(aAncestorFrame) {
+        mAncestorFrame(aAncestorFrame),
+        mTableType(GetTableTypeFromFrame(aAncestorFrame)) {
     if (aBuilder->IsRetainingDisplayList()) {
       mAncestorFrame->AddDisplayItem(this);
     }
   }
 
-  // Should have an identical argument signature to the above ctor
-  static uint16_t CalculatePerFrameIndex(
-      nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
-      const nsRect& aBackgroundRect,
-      const mozilla::ComputedStyle* aBackgroundStyle, const nscolor& aColor,
-      nsIFrame* aAncestorFrame) {
-    return static_cast<uint8_t>(GetTableTypeFromFrame(aAncestorFrame));
-  }
-
   ~nsDisplayTableBackgroundColor() override {
     if (mAncestorFrame) {
       mAncestorFrame->RemoveDisplayItem(this);
     }
   }
 
   NS_DISPLAY_DECL_NAME("TableBackgroundColor", TYPE_TABLE_BACKGROUND_COLOR)
 
@@ -5092,22 +5051,27 @@ class nsDisplayTableBackgroundColor : pu
   void RemoveFrame(nsIFrame* aFrame) override {
     if (aFrame == mAncestorFrame) {
       mAncestorFrame = nullptr;
       SetDeletedFrame();
     }
     nsDisplayBackgroundColor::RemoveFrame(aFrame);
   }
 
+  uint16_t CalculatePerFrameKey() const override {
+    return static_cast<uint8_t>(mTableType);
+  }
+
   bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) override {
     return false;
   }
 
  protected:
   nsIFrame* mAncestorFrame;
+  TableType mTableType;
 };
 
 /**
  * The standard display item to paint the outer CSS box-shadows of a frame.
  */
 class nsDisplayBoxShadowOuter final : public nsPaintedDisplayItem {
  public:
   nsDisplayBoxShadowOuter(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
@@ -5294,49 +5258,37 @@ class nsDisplayEventReceiver : public ns
 class nsDisplayCompositorHitTestInfo : public nsDisplayHitTestInfoItem {
  public:
   nsDisplayCompositorHitTestInfo(
       nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
       const mozilla::gfx::CompositorHitTestInfo& aHitTestFlags,
       uint16_t aIndex = 0,
       const mozilla::Maybe<nsRect>& aArea = mozilla::Nothing());
 
-  // Should have the same argument signature as the above ctor
-  static uint16_t CalculatePerFrameIndex(
-      nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
-      const mozilla::gfx::CompositorHitTestInfo& aHitTestFlags,
-      uint16_t aIndex = 0,
-      const mozilla::Maybe<nsRect>& aArea = mozilla::Nothing());
-
   nsDisplayCompositorHitTestInfo(
       nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
       mozilla::UniquePtr<HitTestInfo>&& aHitTestInfo);
 
-  // Should have the same argument signature as the above ctor
-  static uint16_t CalculatePerFrameIndex(
-      nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
-      mozilla::UniquePtr<HitTestInfo>&& aHitTestInfo);
-
 #ifdef NS_BUILD_REFCNT_LOGGING
   ~nsDisplayCompositorHitTestInfo() override {
     MOZ_COUNT_DTOR(nsDisplayCompositorHitTestInfo);
   }
 #endif
 
   NS_DISPLAY_DECL_NAME("CompositorHitTestInfo", TYPE_COMPOSITOR_HITTEST_INFO)
 
   void InitializeScrollTarget(nsDisplayListBuilder* aBuilder);
 
   bool CreateWebRenderCommands(
       mozilla::wr::DisplayListBuilder& aBuilder,
       mozilla::wr::IpcResourceUpdateQueue& aResources,
       const StackingContextHelper& aSc,
       mozilla::layers::RenderRootStateManager* aManager,
       nsDisplayListBuilder* aDisplayListBuilder) override;
-
+  uint16_t CalculatePerFrameKey() const override;
   int32_t ZIndex() const override;
   void SetOverrideZIndex(int32_t aZIndex);
 
   /**
    * ApplyOpacity() is overriden for opacity flattening.
    */
   void ApplyOpacity(nsDisplayListBuilder* aBuilder, float aOpacity,
                     const DisplayItemClipChain* aClip) override {}
@@ -5348,16 +5300,17 @@ class nsDisplayCompositorHitTestInfo : p
 
   nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override {
     *aSnap = false;
     return nsRect();
   }
 
  private:
   mozilla::Maybe<mozilla::layers::ScrollableLayerGuid::ViewID> mScrollTarget;
+  uint16_t mIndex;
   mozilla::Maybe<int32_t> mOverrideZIndex;
   int32_t mAppUnitsPerDevPixel;
 };
 
 /**
  * A class that lets you wrap a display list as a display item.
  *
  * GetUnderlyingFrame() is troublesome for wrapped lists because if the wrapped
@@ -5374,78 +5327,52 @@ class nsDisplayCompositorHitTestInfo : p
 class nsDisplayWrapList : public nsDisplayHitTestInfoItem {
  public:
   /**
    * Takes all the items from aList and puts them in our list.
    */
   nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                     nsDisplayList* aList);
 
-  // Should have an identical argument signature to the above ctor
-  static uint16_t CalculatePerFrameIndex(nsDisplayListBuilder* aBuilder,
-                                         nsIFrame* aFrame,
-                                         nsDisplayList* aList) {
-    return 0;
-  }
-
   nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                     nsDisplayItem* aItem);
 
-  // Should have an identical argument signature to the above ctor
-  static uint16_t CalculatePerFrameIndex(nsDisplayListBuilder* aBuilder,
-                                         nsIFrame* aFrame,
-                                         nsDisplayItem* aItem) {
-    return 0;
-  }
-
   nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                     nsDisplayList* aList,
                     const ActiveScrolledRoot* aActiveScrolledRoot,
                     bool aClearClipChain = false, uint16_t aIndex = 0);
 
-  // Should have an identical argument signature to the above ctor
-  static uint16_t CalculatePerFrameIndex(
-      nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
-      const ActiveScrolledRoot* aActiveScrolledRoot,
-      bool aClearClipChain = false, uint16_t aIndex = 0) {
-    return aIndex;
-  }
-
   nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
       : nsDisplayHitTestInfoItem(aBuilder, aFrame),
         mFrameActiveScrolledRoot(aBuilder->CurrentActiveScrolledRoot()),
         mOverrideZIndex(0),
+        mIndex(0),
         mHasZIndexOverride(false) {
     MOZ_COUNT_CTOR(nsDisplayWrapList);
     mBaseBuildingRect = GetBuildingRect();
     mListPtr = &mList;
   }
 
-  // Should have an identical argument signature to the above ctor
-  static uint16_t CalculatePerFrameIndex(nsDisplayListBuilder* aBuilder,
-                                         nsIFrame* aFrame) {
-    return 0;
-  }
-
   nsDisplayWrapList() = delete;
 
   /**
    * A custom copy-constructor that does not copy mList, as this would mutate
    * the other item.
    */
   nsDisplayWrapList(const nsDisplayWrapList& aOther) = delete;
   nsDisplayWrapList(nsDisplayListBuilder* aBuilder,
                     const nsDisplayWrapList& aOther)
       : nsDisplayHitTestInfoItem(aBuilder, aOther),
         mListPtr(&mList),
         mFrameActiveScrolledRoot(aOther.mFrameActiveScrolledRoot),
         mMergedFrames(aOther.mMergedFrames),
         mBounds(aOther.mBounds),
         mBaseBuildingRect(aOther.mBaseBuildingRect),
         mOverrideZIndex(aOther.mOverrideZIndex),
+        mIndex(aOther.mIndex),
         mHasZIndexOverride(aOther.mHasZIndexOverride),
         mClearingClipChain(aOther.mClearingClipChain) {
     MOZ_COUNT_CTOR(nsDisplayWrapList);
   }
 
   ~nsDisplayWrapList() override;
 
   NS_DISPLAY_DECL_NAME("WrapList", TYPE_WRAP_LIST)
@@ -5509,16 +5436,18 @@ class nsDisplayWrapList : public nsDispl
   nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
                            bool* aSnap) const override;
   mozilla::Maybe<nscolor> IsUniform(
       nsDisplayListBuilder* aBuilder) const override;
   void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
   bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                          nsRegion* aVisibleRegion) override;
 
+  uint16_t CalculatePerFrameKey() const override { return mIndex; }
+
   /**
    * Checks if the given display item can be merged with this item.
    * @return true if the merging is possible, otherwise false.
    */
   virtual bool CanMerge(const nsDisplayItem* aItem) const { return false; }
 
   /**
    * Try to merge with the other item (which is below us in the display
@@ -5629,16 +5558,17 @@ class nsDisplayWrapList : public nsDispl
   // The frames from items that have been merged into this item, excluding
   // this item's own frame.
   nsTArray<nsIFrame*> mMergedFrames;
   nsRect mBounds;
   // Displaylist building rect contributed by this display item itself.
   // Our mBuildingRect may include the visible areas of children.
   nsRect mBaseBuildingRect;
   int32_t mOverrideZIndex;
+  uint16_t mIndex;
   bool mHasZIndexOverride;
   bool mClearingClipChain = false;
 
  private:
   NS_DISPLAY_ALLOW_CLONING()
   friend class nsDisplayListBuilder;
 };
 
@@ -5806,30 +5736,21 @@ class nsDisplayOpacity : public nsDispla
 };
 
 class nsDisplayBlendMode : public nsDisplayWrapList {
  public:
   nsDisplayBlendMode(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                      nsDisplayList* aList, uint8_t aBlendMode,
                      const ActiveScrolledRoot* aActiveScrolledRoot,
                      uint16_t aIndex = 0);
-
-  // Should have the same argument signature as the above ctor
-  static uint16_t CalculatePerFrameIndex(
-      nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
-      uint8_t aBlendMode, const ActiveScrolledRoot* aActiveScrolledRoot,
-      uint16_t aIndex = 0) {
-    return aIndex;
-  }
-
   nsDisplayBlendMode(nsDisplayListBuilder* aBuilder,
                      const nsDisplayBlendMode& aOther)
       : nsDisplayWrapList(aBuilder, aOther),
         mBlendMode(aOther.mBlendMode),
-        mIsBackgroundBlendMode(aOther.mIsBackgroundBlendMode) {
+        mIndex(aOther.mIndex) {
     MOZ_COUNT_CTOR(nsDisplayBlendMode);
   }
 
 #ifdef NS_BUILD_REFCNT_LOGGING
   ~nsDisplayBlendMode() override { MOZ_COUNT_DTOR(nsDisplayBlendMode); }
 #endif
 
   NS_DISPLAY_DECL_NAME("BlendMode", TYPE_BLEND_MODE)
@@ -5841,16 +5762,18 @@ class nsDisplayBlendMode : public nsDisp
       const ContainerLayerParameters& aContainerParameters) override;
   void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                  const nsDisplayItemGeometry* aGeometry,
                                  nsRegion* aInvalidRegion) const override {
     // We don't need to compute an invalidation region since we have
     // LayerTreeInvalidation
   }
 
+  uint16_t CalculatePerFrameKey() const override { return mIndex; }
+
   LayerState GetLayerState(
       nsDisplayListBuilder* aBuilder, LayerManager* aManager,
       const ContainerLayerParameters& aParameters) override;
   bool CreateWebRenderCommands(
       mozilla::wr::DisplayListBuilder& aBuilder,
       mozilla::wr::IpcResourceUpdateQueue& aResources,
       const StackingContextHelper& aSc,
       mozilla::layers::RenderRootStateManager* aManager,
@@ -5863,49 +5786,42 @@ class nsDisplayBlendMode : public nsDisp
   bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
     return false;
   }
 
   mozilla::gfx::CompositionOp BlendMode();
 
  protected:
   uint8_t mBlendMode;
-  bool mIsBackgroundBlendMode;
+  uint16_t mIndex;
 
  private:
   NS_DISPLAY_ALLOW_CLONING()
 };
 
 class nsDisplayTableBlendMode : public nsDisplayBlendMode {
  public:
   nsDisplayTableBlendMode(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                           nsDisplayList* aList, uint8_t aBlendMode,
                           const ActiveScrolledRoot* aActiveScrolledRoot,
                           uint16_t aIndex, nsIFrame* aAncestorFrame)
       : nsDisplayBlendMode(aBuilder, aFrame, aList, aBlendMode,
                            aActiveScrolledRoot, aIndex),
-        mAncestorFrame(aAncestorFrame) {
+        mAncestorFrame(aAncestorFrame),
+        mTableType(GetTableTypeFromFrame(aAncestorFrame)) {
     if (aBuilder->IsRetainingDisplayList()) {
       mAncestorFrame->AddDisplayItem(this);
     }
   }
 
-  // Should have the same argument signature as the above ctor
-  static uint16_t CalculatePerFrameIndex(
-      nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
-      uint8_t aBlendMode, const ActiveScrolledRoot* aActiveScrolledRoot,
-      uint16_t aIndex, nsIFrame* aAncestorFrame) {
-    return CalculateTablePerFrameKey(aIndex,
-                                     GetTableTypeFromFrame(aAncestorFrame));
-  }
-
   nsDisplayTableBlendMode(nsDisplayListBuilder* aBuilder,
                           const nsDisplayTableBlendMode& aOther)
       : nsDisplayBlendMode(aBuilder, aOther),
-        mAncestorFrame(aOther.mAncestorFrame) {
+        mAncestorFrame(aOther.mAncestorFrame),
+        mTableType(aOther.mTableType) {
     if (aBuilder->IsRetainingDisplayList()) {
       mAncestorFrame->AddDisplayItem(this);
     }
   }
 
   ~nsDisplayTableBlendMode() override {
     if (mAncestorFrame) {
       mAncestorFrame->RemoveDisplayItem(this);
@@ -5919,18 +5835,23 @@ class nsDisplayTableBlendMode : public n
   void RemoveFrame(nsIFrame* aFrame) override {
     if (aFrame == mAncestorFrame) {
       mAncestorFrame = nullptr;
       SetDeletedFrame();
     }
     nsDisplayBlendMode::RemoveFrame(aFrame);
   }
 
+  uint16_t CalculatePerFrameKey() const override {
+    return CalculateTablePerFrameKey(mIndex, mTableType);
+  }
+
  protected:
   nsIFrame* mAncestorFrame;
+  TableType mTableType;
 
  private:
   NS_DISPLAY_ALLOW_CLONING()
 };
 
 class nsDisplayBlendContainer : public nsDisplayWrapList {
  public:
   static nsDisplayBlendContainer* CreateForMixBlendMode(
@@ -5971,29 +5892,25 @@ class nsDisplayBlendContainer : public n
                static_cast<const nsDisplayBlendContainer*>(aItem)
                    ->mIsForBackground;
   }
 
   bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
     return false;
   }
 
+  uint16_t CalculatePerFrameKey() const override {
+    return mIsForBackground ? 1 : 0;
+  }
+
  protected:
   nsDisplayBlendContainer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                           nsDisplayList* aList,
                           const ActiveScrolledRoot* aActiveScrolledRoot,
                           bool aIsForBackground);
-
-  // Should have an identical argument signature to the above ctor
-  static uint16_t CalculatePerFrameIndex(
-      nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
-      const ActiveScrolledRoot* aActiveScrolledRoot, bool aIsForBackground) {
-    return aIsForBackground ? 1 : 0;
-  }
-
   nsDisplayBlendContainer(nsDisplayListBuilder* aBuilder,
                           const nsDisplayBlendContainer& aOther)
       : nsDisplayWrapList(aBuilder, aOther),
         mIsForBackground(aOther.mIsForBackground) {
     MOZ_COUNT_CTOR(nsDisplayBlendContainer);
   }
 
   // Used to distinguish containers created at building stacking
@@ -6017,49 +5934,48 @@ class nsDisplayTableBlendContainer : pub
   void RemoveFrame(nsIFrame* aFrame) override {
     if (aFrame == mAncestorFrame) {
       mAncestorFrame = nullptr;
       SetDeletedFrame();
     }
     nsDisplayBlendContainer::RemoveFrame(aFrame);
   }
 
+  uint16_t CalculatePerFrameKey() const override {
+    return static_cast<uint8_t>(mTableType);
+  }
+
  protected:
   nsDisplayTableBlendContainer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                                nsDisplayList* aList,
                                const ActiveScrolledRoot* aActiveScrolledRoot,
                                bool aIsForBackground, nsIFrame* aAncestorFrame)
       : nsDisplayBlendContainer(aBuilder, aFrame, aList, aActiveScrolledRoot,
                                 aIsForBackground),
-        mAncestorFrame(aAncestorFrame) {
+        mAncestorFrame(aAncestorFrame),
+        mTableType(GetTableTypeFromFrame(aAncestorFrame)) {
     if (aBuilder->IsRetainingDisplayList()) {
       mAncestorFrame->AddDisplayItem(this);
     }
   }
 
-  // Should have an identical argument signature to the above ctor
-  static uint16_t CalculatePerFrameIndex(
-      nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
-      const ActiveScrolledRoot* aActiveScrolledRoot, bool aIsForBackground,
-      nsIFrame* aAncestorFrame) {
-    return static_cast<uint8_t>(GetTableTypeFromFrame(aAncestorFrame));
-  }
-
   nsDisplayTableBlendContainer(nsDisplayListBuilder* aBuilder,
                                const nsDisplayTableBlendContainer& aOther)
       : nsDisplayBlendContainer(aBuilder, aOther),
-        mAncestorFrame(aOther.mAncestorFrame) {}
+        mAncestorFrame(aOther.mAncestorFrame),
+        mTableType(aOther.mTableType) {}
 
   ~nsDisplayTableBlendContainer() override {
     if (mAncestorFrame) {
       mAncestorFrame->RemoveDisplayItem(this);
     }
   }
 
   nsIFrame* mAncestorFrame;
+  TableType mTableType;
 
  private:
   NS_DISPLAY_ALLOW_CLONING()
 };
 
 /**
  * nsDisplayOwnLayer constructor flags. If we nest this class inside
  * nsDisplayOwnLayer then we can't forward-declare it up at the top of this
@@ -6105,34 +6021,24 @@ class nsDisplayOwnLayer : public nsDispl
   nsDisplayOwnLayer(
       nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
       const ActiveScrolledRoot* aActiveScrolledRoot,
       nsDisplayOwnLayerFlags aFlags = nsDisplayOwnLayerFlags::None,
       const ScrollbarData& aScrollbarData = ScrollbarData{},
       bool aForceActive = true, bool aClearClipChain = false,
       uint16_t aIndex = 0);
 
-  // Should have an identical argument signature to the above ctor
-  static uint16_t CalculatePerFrameIndex(
-      nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
-      const ActiveScrolledRoot* aActiveScrolledRoot,
-      nsDisplayOwnLayerFlags aFlags = nsDisplayOwnLayerFlags::None,
-      const ScrollbarData& aScrollbarData = ScrollbarData{},
-      bool aForceActive = true, bool aClearClipChain = false,
-      uint16_t aIndex = 0) {
-    return aIndex;
-  }
-
   nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder,
                     const nsDisplayOwnLayer& aOther)
       : nsDisplayWrapList(aBuilder, aOther),
         mFlags(aOther.mFlags),
         mScrollbarData(aOther.mScrollbarData),
         mForceActive(aOther.mForceActive),
-        mWrAnimationId(aOther.mWrAnimationId) {
+        mWrAnimationId(aOther.mWrAnimationId),
+        mIndex(aOther.mIndex) {
     MOZ_COUNT_CTOR(nsDisplayOwnLayer);
   }
 
 #ifdef NS_BUILD_REFCNT_LOGGING
   ~nsDisplayOwnLayer() override { MOZ_COUNT_DTOR(nsDisplayOwnLayer); }
 #endif
 
   NS_DISPLAY_DECL_NAME("OwnLayer", TYPE_OWN_LAYER)
@@ -6153,16 +6059,18 @@ class nsDisplayOwnLayer : public nsDispl
       nsDisplayListBuilder* aBuilder, LayerManager* aManager,
       const ContainerLayerParameters& aParameters) override;
 
   bool CanMerge(const nsDisplayItem* aItem) const override {
     // Don't allow merging, each sublist must have its own layer
     return false;
   }
 
+  uint16_t CalculatePerFrameKey() const override { return mIndex; }
+
   bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
     return false;
   }
 
   void WriteDebugInfo(std::stringstream& aStream) override;
   nsDisplayOwnLayerFlags GetFlags() { return mFlags; }
   bool IsScrollThumbLayer() const;
   bool IsScrollbarContainer() const;
@@ -6176,32 +6084,25 @@ class nsDisplayOwnLayer : public nsDispl
    * scrollbar container layer, mScrollbarData stores information
    * about the scrollbar. Otherwise, mScrollbarData will be
    * default-constructed (in particular with mDirection == Nothing())
    * and can be ignored.
    */
   ScrollbarData mScrollbarData;
   bool mForceActive;
   uint64_t mWrAnimationId;
+  uint16_t mIndex;
 };
 
 class nsDisplayRenderRoot : public nsDisplayWrapList {
   nsDisplayRenderRoot(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                       nsDisplayList* aList,
                       const ActiveScrolledRoot* aActiveScrolledRoot,
                       mozilla::wr::RenderRoot aRenderRoot);
 
-  // Should have an identical argument signature to the above ctor
-  static uint16_t CalculatePerFrameIndex(
-      nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
-      const ActiveScrolledRoot* aActiveScrolledRoot,
-      mozilla::wr::RenderRoot aRenderRoot) {
-    return 0;
-  }
-
 #ifdef NS_BUILD_REFCNT_LOGGING
   ~nsDisplayRenderRoot() override { MOZ_COUNT_DTOR(nsDisplayRenderRoot); }
 #endif
 
   NS_DISPLAY_DECL_NAME("RenderRoot", TYPE_RENDER_ROOT)
 
   void InvalidateCachedChildInfo(nsDisplayListBuilder* aBuilder) override;
   void Destroy(nsDisplayListBuilder* aBuilder) override;
@@ -6235,26 +6136,16 @@ class nsDisplayRenderRoot : public nsDis
  * nsDisplayOwnLayer, except that it always populates the FrameMetrics instance
  * on the ContainerLayer it builds.
  */
 class nsDisplaySubDocument : public nsDisplayOwnLayer {
  public:
   nsDisplaySubDocument(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                        nsSubDocumentFrame* aSubDocFrame, nsDisplayList* aList,
                        nsDisplayOwnLayerFlags aFlags);
-
-  // Should have an identical argument signature to the above ctor
-  static uint16_t CalculatePerFrameIndex(nsDisplayListBuilder* aBuilder,
-                                         nsIFrame* aFrame,
-                                         nsSubDocumentFrame* aSubDocFrame,
-                                         nsDisplayList* aList,
-                                         nsDisplayOwnLayerFlags aFlags) {
-    return 0;
-  }
-
   ~nsDisplaySubDocument() override;
 
   NS_DISPLAY_DECL_NAME("SubDocument", TYPE_SUBDOCUMENT)
 
   nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
 
   virtual nsSubDocumentFrame* SubDocumentFrame() { return mSubDocFrame; }
 
@@ -6325,25 +6216,16 @@ class nsDisplayResolution : public nsDis
  * position-related metadata set on it.
  */
 class nsDisplayStickyPosition : public nsDisplayOwnLayer {
  public:
   nsDisplayStickyPosition(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                           nsDisplayList* aList,
                           const ActiveScrolledRoot* aActiveScrolledRoot,
                           const ActiveScrolledRoot* aContainerASR);
-
-  // Should have an identical argument signature to the above ctor
-  static uint16_t CalculatePerFrameIndex(
-      nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
-      const ActiveScrolledRoot* aActiveScrolledRoot,
-      const ActiveScrolledRoot* aContainerASR) {
-    return 0;
-  }
-
   nsDisplayStickyPosition(nsDisplayListBuilder* aBuilder,
                           const nsDisplayStickyPosition& aOther)
       : nsDisplayOwnLayer(aBuilder, aOther),
         mContainerASR(aOther.mContainerASR) {
     MOZ_COUNT_CTOR(nsDisplayStickyPosition);
   }
 
 #ifdef NS_BUILD_REFCNT_LOGGING
@@ -6384,31 +6266,23 @@ class nsDisplayStickyPosition : public n
 };
 
 class nsDisplayFixedPosition : public nsDisplayOwnLayer {
  public:
   nsDisplayFixedPosition(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                          nsDisplayList* aList,
                          const ActiveScrolledRoot* aActiveScrolledRoot,
                          const ActiveScrolledRoot* aContainerASR);
-
-  // Should have an identical argument signature to the above ctor
-  static uint16_t CalculatePerFrameIndex(
-      nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
-      const ActiveScrolledRoot* aActiveScrolledRoot,
-      const ActiveScrolledRoot* aContainerASR) {
-    return 0;
-  }
-
   nsDisplayFixedPosition(nsDisplayListBuilder* aBuilder,
                          const nsDisplayFixedPosition& aOther)
       : nsDisplayOwnLayer(aBuilder, aOther),
         mAnimatedGeometryRootForScrollMetadata(
             aOther.mAnimatedGeometryRootForScrollMetadata),
         mContainerASR(aOther.mContainerASR),
+        mIndex(aOther.mIndex),
         mIsFixedBackground(aOther.mIsFixedBackground) {
     MOZ_COUNT_CTOR(nsDisplayFixedPosition);
   }
 
   static nsDisplayFixedPosition* CreateForFixedBackground(
       nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
       nsDisplayBackgroundImage* aImage, uint16_t aIndex);
 
@@ -6427,16 +6301,18 @@ class nsDisplayFixedPosition : public ns
       const ContainerLayerParameters& aParameters) override {
     return mozilla::LayerState::LAYER_ACTIVE_FORCE;
   }
 
   bool ShouldFixToViewport(nsDisplayListBuilder* aBuilder) const override {
     return mIsFixedBackground;
   }
 
+  uint16_t CalculatePerFrameKey() const override { return mIndex; }
+
   AnimatedGeometryRoot* AnimatedGeometryRootForScrollMetadata() const override {
     return mAnimatedGeometryRootForScrollMetadata;
   }
 
   bool CreateWebRenderCommands(
       mozilla::wr::DisplayListBuilder& aBuilder,
       mozilla::wr::IpcResourceUpdateQueue& aResources,
       const StackingContextHelper& aSc,
@@ -6446,29 +6322,22 @@ class nsDisplayFixedPosition : public ns
       mozilla::layers::WebRenderScrollData* aData,
       mozilla::layers::WebRenderLayerScrollData* aLayerData) override;
   void WriteDebugInfo(std::stringstream& aStream) override;
 
  protected:
   // For background-attachment:fixed
   nsDisplayFixedPosition(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                          nsDisplayList* aList, uint16_t aIndex);
-
-  // Should have an identical argument signature to the above ctor
-  static uint16_t CalculatePerFrameIndex(nsDisplayListBuilder* aBuilder,
-                                         nsIFrame* aFrame, nsDisplayList* aList,
-                                         uint16_t aIndex) {
-    return aIndex;
-  }
-
   void Init(nsDisplayListBuilder* aBuilder);
   ViewID GetScrollTargetId();
 
   RefPtr<AnimatedGeometryRoot> mAnimatedGeometryRootForScrollMetadata;
   RefPtr<const ActiveScrolledRoot> mContainerASR;
+  uint16_t mIndex;
   bool mIsFixedBackground;
 
  private:
   NS_DISPLAY_ALLOW_CLONING()
 };
 
 class nsDisplayTableFixedPosition : public nsDisplayFixedPosition {
  public:
@@ -6484,64 +6353,54 @@ class nsDisplayTableFixedPosition : publ
   void RemoveFrame(nsIFrame* aFrame) override {
     if (aFrame == mAncestorFrame) {
       mAncestorFrame = nullptr;
       SetDeletedFrame();
     }
     nsDisplayFixedPosition::RemoveFrame(aFrame);
   }
 
+  uint16_t CalculatePerFrameKey() const override {
+    return CalculateTablePerFrameKey(mIndex, mTableType);
+  }
+
  protected:
   nsDisplayTableFixedPosition(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                               nsDisplayList* aList, uint16_t aIndex,
                               nsIFrame* aAncestorFrame);
 
-  // Should have an identical argument signature to the above ctor
-  static uint16_t CalculatePerFrameIndex(nsDisplayListBuilder* aBuilder,
-                                         nsIFrame* aFrame, nsDisplayList* aList,
-                                         uint16_t aIndex,
-                                         nsIFrame* aAncestorFrame) {
-    return CalculateTablePerFrameKey(aIndex,
-                                     GetTableTypeFromFrame(aAncestorFrame));
-  }
-
   nsDisplayTableFixedPosition(nsDisplayListBuilder* aBuilder,
                               const nsDisplayTableFixedPosition& aOther)
       : nsDisplayFixedPosition(aBuilder, aOther),
-        mAncestorFrame(aOther.mAncestorFrame) {}
+        mAncestorFrame(aOther.mAncestorFrame),
+        mTableType(aOther.mTableType) {}
 
   ~nsDisplayTableFixedPosition() override {
     if (mAncestorFrame) {
       mAncestorFrame->RemoveDisplayItem(this);
     }
   }
 
   nsIFrame* mAncestorFrame;
+  TableType mTableType;
 
  private:
   NS_DISPLAY_ALLOW_CLONING()
 };
 
 /**
  * This creates an empty scrollable layer. It has no child layers.
  * It is used to record the existence of a scrollable frame in the layer
  * tree.
  */
 class nsDisplayScrollInfoLayer : public nsDisplayWrapList {
  public:
   nsDisplayScrollInfoLayer(nsDisplayListBuilder* aBuilder,
                            nsIFrame* aScrolledFrame, nsIFrame* aScrollFrame);
 
-  // Should have an identical argument signature to the above ctor
-  static uint16_t CalculatePerFrameIndex(nsDisplayListBuilder* aBuilder,
-                                         nsIFrame* aScrolledFrame,
-                                         nsIFrame* aScrollFrame) {
-    return 0;
-  }
-
 #ifdef NS_BUILD_REFCNT_LOGGING
   ~nsDisplayScrollInfoLayer() override {
     MOZ_COUNT_DTOR(nsDisplayScrollInfoLayer);
   }
 #endif
 
   NS_DISPLAY_DECL_NAME("ScrollInfoLayer", TYPE_SCROLL_INFO_LAYER)
 
@@ -6593,25 +6452,16 @@ class nsDisplayZoom : public nsDisplaySu
    * Add UserData to the created ContainerLayer, so that invalidations
    * for this layer are send to our nsPresContext.
    */
   nsDisplayZoom(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                 nsSubDocumentFrame* aSubDocFrame, nsDisplayList* aList,
                 int32_t aAPD, int32_t aParentAPD,
                 nsDisplayOwnLayerFlags aFlags = nsDisplayOwnLayerFlags::None);
 
-  // Should have an identical argument signature to the above ctor
-  static uint16_t CalculatePerFrameIndex(
-      nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
-      nsSubDocumentFrame* aSubDocFrame, nsDisplayList* aList, int32_t aAPD,
-      int32_t aParentAPD,
-      nsDisplayOwnLayerFlags aFlags = nsDisplayOwnLayerFlags::None) {
-    return 0;
-  }
-
 #ifdef NS_BUILD_REFCNT_LOGGING
   ~nsDisplayZoom() override { MOZ_COUNT_DTOR(nsDisplayZoom); }
 #endif
 
   NS_DISPLAY_DECL_NAME("Zoom", TYPE_ZOOM)
 
   nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override;
   void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
@@ -6641,25 +6491,16 @@ class nsDisplayZoom : public nsDisplaySu
  * are scrolled. This item creates a container layer.
  */
 class nsDisplayAsyncZoom : public nsDisplayOwnLayer {
  public:
   nsDisplayAsyncZoom(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                      nsDisplayList* aList,
                      const ActiveScrolledRoot* aActiveScrolledRoot,
                      mozilla::layers::FrameMetrics::ViewID aViewID);
-
-  // Should have an identical argument signature to the above ctor
-  static uint16_t CalculatePerFrameIndex(
-      nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
-      const ActiveScrolledRoot* aActiveScrolledRoot,
-      mozilla::layers::FrameMetrics::ViewID aViewID) {
-    return 0;
-  }
-
   nsDisplayAsyncZoom(nsDisplayListBuilder* aBuilder,
                      const nsDisplayAsyncZoom& aOther)
       : nsDisplayOwnLayer(aBuilder, aOther), mViewID(aOther.mViewID) {
     MOZ_COUNT_CTOR(nsDisplayAsyncZoom);
   }
 
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayAsyncZoom();
@@ -6883,22 +6724,16 @@ class nsDisplayBackdropFilters : public 
  public:
   nsDisplayBackdropFilters(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                            nsDisplayList* aList, const nsRect& aBackdropRect)
       : nsDisplayWrapList(aBuilder, aFrame, aList),
         mBackdropRect(aBackdropRect) {
     MOZ_COUNT_CTOR(nsDisplayBackdropFilters);
   }
 
-  static uint16_t CalculatePerFrameIndex(nsDisplayListBuilder* aBuilder,
-                                         nsIFrame* aFrame, nsDisplayList* aList,
-                                         const nsRect& aBackdropRect) {
-    return 0;
-  }
-
 #ifdef NS_BUILD_REFCNT_LOGGING
   ~nsDisplayBackdropFilters() override {
     MOZ_COUNT_DTOR(nsDisplayBackdropFilters);
   }
 #endif
 
   NS_DISPLAY_DECL_NAME("BackdropFilter", TYPE_BACKDROP_FILTER)
 
@@ -7039,50 +6874,25 @@ class nsDisplayTransform : public nsDisp
 
   /* Constructor accepts a display list, empties it, and wraps it up.  It also
    * ferries the underlying frame to the nsDisplayItem constructor.
    */
   nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                      nsDisplayList* aList, const nsRect& aChildrenBuildingRect,
                      uint16_t aIndex);
 
-  // Should have an identical argument signature to the above ctor
-  static uint16_t CalculatePerFrameIndex(nsDisplayListBuilder* aBuilder,
-                                         nsIFrame* aFrame, nsDisplayList* aList,
-                                         const nsRect& aChildrenBuildingRect,
-                                         uint16_t aIndex) {
-    return aIndex;
-  }
-
   nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                      nsDisplayList* aList, const nsRect& aChildrenBuildingRect,
                      uint16_t aIndex, bool aAllowAsyncAnimation);
 
-  // Should have an identical argument signature to the above ctor
-  static uint16_t CalculatePerFrameIndex(nsDisplayListBuilder* aBuilder,
-                                         nsIFrame* aFrame, nsDisplayList* aList,
-                                         const nsRect& aChildrenBuildingRect,
-                                         uint16_t aIndex,
-                                         bool aAllowAsyncAnimation) {
-    return aIndex;
-  }
-
   nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                      nsDisplayList* aList, const nsRect& aChildrenBuildingRect,
                      uint16_t aIndex,
                      ComputeTransformFunction aTransformGetter);
 
-  // Should have an identical argument signature to the above ctor
-  static uint16_t CalculatePerFrameIndex(
-      nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
-      const nsRect& aChildrenBuildingRect, uint16_t aIndex,
-      ComputeTransformFunction aTransformGetter) {
-    return aIndex;
-  }
-
 #ifdef NS_BUILD_REFCNT_LOGGING
   ~nsDisplayTransform() override { MOZ_COUNT_DTOR(nsDisplayTransform); }
 #endif
 
   NS_DISPLAY_DECL_NAME("nsDisplayTransform", TYPE_TRANSFORM)
 
   void RestoreState() override {
     nsDisplayHitTestInfoItem::RestoreState();
@@ -7138,16 +6948,18 @@ class nsDisplayTransform : public nsDisp
       mozilla::layers::RenderRootStateManager* aManager,
       nsDisplayListBuilder* aDisplayListBuilder) override;
   bool UpdateScrollData(
       mozilla::layers::WebRenderScrollData* aData,
       mozilla::layers::WebRenderLayerScrollData* aLayerData) override;
   bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                          nsRegion* aVisibleRegion) override;
 
+  uint16_t CalculatePerFrameKey() const override { return mIndex; }
+
   nsDisplayItemGeometry* AllocateGeometry(
       nsDisplayListBuilder* aBuilder) override {
     return new nsDisplayTransformGeometry(
         this, aBuilder, GetTransformForRendering(),
         mFrame->PresContext()->AppUnitsPerDevPixel());
   }
 
   void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
@@ -7390,16 +7202,17 @@ class nsDisplayTransform : public nsDisp
   mutable mozilla::Maybe<Matrix4x4Flagged> mInverseTransform;
   // Accumulated transform of ancestors on the preserves-3d chain.
   mozilla::UniquePtr<Matrix4x4> mTransformPreserves3D;
   ComputeTransformFunction mTransformGetter;
   RefPtr<AnimatedGeometryRoot> mAnimatedGeometryRootForChildren;
   RefPtr<AnimatedGeometryRoot> mAnimatedGeometryRootForScrollMetadata;
   nsRect mChildrenBuildingRect;
   mutable RetainedDisplayList mChildren;
+  uint16_t mIndex;
 
   // The untransformed bounds of |mChildren|.
   nsRect mChildBounds;
   // The transformed bounds of this display item.
   nsRect mBounds;
   // This item is a separator between 3D rendering contexts, and
   // mTransform have been presetted by the constructor.
   // This also forces us not to extend the 3D context.  Since we don't create a
--- a/layout/xul/nsBoxFrame.cpp
+++ b/layout/xul/nsBoxFrame.cpp
@@ -1258,36 +1258,20 @@ nsresult nsBoxFrame::XULRelayoutChildAtO
 // I've made 'allowevents' affect child elements because that seems the only
 // reasonable thing to do.
 class nsDisplayXULEventRedirector final : public nsDisplayWrapList {
  public:
   nsDisplayXULEventRedirector(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                               nsDisplayItem* aItem, nsIFrame* aTargetFrame)
       : nsDisplayWrapList(aBuilder, aFrame, aItem),
         mTargetFrame(aTargetFrame) {}
-
-  // Should have an identical argument signature to the above ctor
-  static uint16_t CalculatePerFrameIndex(nsDisplayListBuilder* aBuilder,
-                                         nsIFrame* aFrame, nsDisplayItem* aItem,
-                                         nsIFrame* aTargetFrame) {
-    return 0;
-  }
-
   nsDisplayXULEventRedirector(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                               nsDisplayList* aList, nsIFrame* aTargetFrame)
       : nsDisplayWrapList(aBuilder, aFrame, aList),
         mTargetFrame(aTargetFrame) {}
-
-  // Should have an identical argument signature to the above ctor
-  static uint16_t CalculatePerFrameIndex(nsDisplayListBuilder* aBuilder,
-                                         nsIFrame* aFrame, nsDisplayList* aList,
-                                         nsIFrame* aTargetFrame) {
-    return 0;
-  }
-
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState,
                        nsTArray<nsIFrame*>* aOutFrames) override;
   virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
     return false;
   }
   NS_DISPLAY_DECL_NAME("XULEventRedirector", TYPE_XUL_EVENT_REDIRECTOR)
  private: