Bug 1529698 - Part 3: Move DisplayItemData to nsPaintedDisplayItem r=mattwoodrow
authorMiko Mynttinen <mikokm@gmail.com>
Sat, 18 May 2019 20:11:27 +0000
changeset 533273 40280b1c2aff496375f2acf8bae2d4b332f6f404
parent 533272 5d245d6070e0e7fbe338339fe7c12c8042dcb1e7
child 533274 e37407909f92b48af964ac41514a1b58c2ba1ff4
push id11276
push userrgurzau@mozilla.com
push dateMon, 20 May 2019 13:11:24 +0000
treeherdermozilla-beta@847755a7c325 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1529698
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1529698 - Part 3: Move DisplayItemData to nsPaintedDisplayItem r=mattwoodrow Differential Revision: https://phabricator.services.mozilla.com/D30839
layout/painting/FrameLayerBuilder.cpp
layout/painting/FrameLayerBuilder.h
layout/painting/nsDisplayList.cpp
layout/painting/nsDisplayList.h
--- a/layout/painting/FrameLayerBuilder.cpp
+++ b/layout/painting/FrameLayerBuilder.cpp
@@ -279,32 +279,32 @@ void DisplayItemData::EndUpdate(nsAutoPt
   mClip = mItem->GetClip();
   mChangedFrameInvalidations.SetEmpty();
 
   EndUpdate();
 }
 
 void DisplayItemData::BeginUpdate(Layer* aLayer, LayerState aState,
                                   bool aFirstUpdate,
-                                  nsDisplayItem* aItem /* = nullptr */) {
+                                  nsPaintedDisplayItem* aItem /* = nullptr */) {
   bool isReused = false;
   bool isMerged = false;
 
   if (aItem) {
     isReused = !aFirstUpdate ? aItem->IsReused() : false;
 
     const nsDisplayWrapList* wraplist = aItem->AsDisplayWrapList();
     isMerged = wraplist && wraplist->HasMergedFrames();
   }
 
   BeginUpdate(aLayer, aState, aItem, isReused, isMerged);
 }
 
 void DisplayItemData::BeginUpdate(Layer* aLayer, LayerState aState,
-                                  nsDisplayItem* aItem, bool aIsReused,
+                                  nsPaintedDisplayItem* aItem, bool aIsReused,
                                   bool aIsMerged) {
   MOZ_RELEASE_ASSERT(mLayer);
   MOZ_RELEASE_ASSERT(aLayer);
   mLayer = aLayer;
   mOptLayer = nullptr;
   mInactiveManager = nullptr;
   mLayerState = aState;
   mUsed = true;
@@ -585,28 +585,28 @@ class PaintedLayerData {
 #  define FLB_LOG_PAINTED_LAYER_DECISION(...)
 #endif
 
   /**
    * Disables component alpha for |aItem| if the component alpha bounds are not
    * contained in |mOpaqueRegion|. Alternatively if possible, sets
    * |mNeedComponentAlpha| to true for this PaintedLayerData.
    */
-  bool SetupComponentAlpha(ContainerState* aState, nsDisplayItem* aItem,
+  bool SetupComponentAlpha(ContainerState* aState, nsPaintedDisplayItem* aItem,
                            const nsIntRect& aVisibleRect,
                            const TransformClipNode* aTransform);
 
   /**
    * Record that an item has been added to the PaintedLayer, so we
    * need to update our regions.
    * @param aVisibleRect the area of the item that's visible
    * @param aSolidColor if non-null, the visible area of the item is
    * a constant color given by *aSolidColor
    */
-  void Accumulate(ContainerState* aState, nsDisplayItem* aItem,
+  void Accumulate(ContainerState* aState, nsPaintedDisplayItem* aItem,
                   const nsIntRect& aVisibleRect, const nsRect& aContentRect,
                   const DisplayItemClip& aClip, LayerState aLayerState,
                   nsDisplayList* aList, DisplayItemEntryType aType,
                   nsTArray<size_t>& aOpacityIndices,
                   const RefPtr<TransformClipNode>& aTransform);
 
   /**
    * Updates the status of |mTransform| and |aOpacityIndices|, based on |aType|.
@@ -2297,27 +2297,25 @@ void FrameLayerBuilder::WillEndTransacti
     }
   }
 
   data->mInvalidateAllLayers = false;
 }
 
 /* static */
 DisplayItemData* FrameLayerBuilder::GetDisplayItemDataForManager(
-    nsDisplayItem* aItem, LayerManager* aManager) {
-  const SmallPointerArray<DisplayItemData>& array =
-      aItem->Frame()->DisplayItemData();
-  for (uint32_t i = 0; i < array.Length(); i++) {
-    DisplayItemData* item =
-        DisplayItemData::AssertDisplayItemData(array.ElementAt(i));
-    if (item->mDisplayItemKey == aItem->GetPerFrameKey() &&
-        item->mLayer->Manager() == aManager) {
-      return item;
-    }
-  }
+    nsPaintedDisplayItem* aItem, LayerManager* aManager) {
+  for (DisplayItemData* did : aItem->Frame()->DisplayItemData()) {
+    DisplayItemData* data = DisplayItemData::AssertDisplayItemData(did);
+    if (data->mDisplayItemKey == aItem->GetPerFrameKey() &&
+        data->mLayer->Manager() == aManager) {
+      return data;
+    }
+  }
+
   return nullptr;
 }
 
 bool FrameLayerBuilder::HasRetainedDataFor(nsIFrame* aFrame,
                                            uint32_t aDisplayItemKey) {
   const SmallPointerArray<DisplayItemData>& array = aFrame->DisplayItemData();
   for (uint32_t i = 0; i < array.Length(); i++) {
     if (DisplayItemData::AssertDisplayItemData(array.ElementAt(i))
@@ -2835,17 +2833,17 @@ nscolor ContainerState::FindOpaqueBackgr
   *aOutIntersectsLayer = true;
 
   // Scan the candidate's display items.
   nsIntRect deviceRect = aRect;
   nsRect appUnitRect = ToAppUnits(deviceRect, mAppUnitsPerDevPixel);
   appUnitRect.ScaleInverseRoundOut(mParameters.mXScale, mParameters.mYScale);
 
   for (auto& assignedItem : Reversed(aData->mAssignedDisplayItems)) {
-    if (assignedItem.mHasOpacity || assignedItem.mHasTransform) {
+    if (assignedItem.HasOpacity() || assignedItem.HasTransform()) {
       // We cannot easily calculate the opaque background color for items inside
       // a flattened effect.
       continue;
     }
 
     if (IsEffectEndMarker(assignedItem.mType)) {
       // An optimization: the underlying display item for effect markers is the
       // same for both start and end markers. Skip the effect end markers.
@@ -2874,17 +2872,17 @@ nscolor ContainerState::FindOpaqueBackgr
     }
 
     if (item->GetClip().IsRectAffectedByClip(deviceRect, mParameters.mXScale,
                                              mParameters.mYScale,
                                              mAppUnitsPerDevPixel)) {
       return NS_RGBA(0, 0, 0, 0);
     }
 
-    MOZ_ASSERT(!assignedItem.mHasOpacity && !assignedItem.mHasTransform);
+    MOZ_ASSERT(!assignedItem.HasOpacity() && !assignedItem.HasTransform());
     Maybe<nscolor> color = item->IsUniform(mBuilder);
 
     if (color && NS_GET_A(*color) == 255) {
       return *color;
     }
 
     return NS_RGBA(0, 0, 0, 0);
   }
@@ -3681,18 +3679,18 @@ void PaintedLayerData::UpdateEffectStatu
       break;
 #endif
     default:
       break;
   }
 }
 
 bool PaintedLayerData::SetupComponentAlpha(
-    ContainerState* aState, nsDisplayItem* aItem, const nsIntRect& aVisibleRect,
-    const TransformClipNode* aTransform) {
+    ContainerState* aState, nsPaintedDisplayItem* aItem,
+    const nsIntRect& aVisibleRect, const TransformClipNode* aTransform) {
   nsRect componentAlphaBounds =
       aItem->GetComponentAlphaBounds(aState->mBuilder);
 
   if (componentAlphaBounds.IsEmpty()) {
     // The item does not require component alpha, nothing do do here.
     return false;
   }
 
@@ -3723,38 +3721,35 @@ bool PaintedLayerData::SetupComponentAlp
       aItem->DisableComponentAlpha();
       return false;
     }
   }
 
   return true;
 }
 
-void PaintedLayerData::Accumulate(ContainerState* aState, nsDisplayItem* aItem,
-                                  const nsIntRect& aVisibleRect,
-                                  const nsRect& aContentRect,
-                                  const DisplayItemClip& aClip,
-                                  LayerState aLayerState, nsDisplayList* aList,
-                                  DisplayItemEntryType aType,
-                                  nsTArray<size_t>& aOpacityIndices,
-                                  const RefPtr<TransformClipNode>& aTransform) {
-  MOZ_ASSERT(aType != DisplayItemEntryType::HitTestInfo,
-             "Should have handled hit test items earlier!");
+void PaintedLayerData::Accumulate(
+    ContainerState* aState, nsPaintedDisplayItem* aItem,
+    const nsIntRect& aVisibleRect, const nsRect& aContentRect,
+    const DisplayItemClip& aClip, LayerState aLayerState, nsDisplayList* aList,
+    DisplayItemEntryType aType, nsTArray<size_t>& aOpacityIndices,
+    const RefPtr<TransformClipNode>& aTransform) {
+  // If aItem is nullptr, the cast to nsPaintedDisplayItem failed.
+  MOZ_ASSERT(aItem, "Can only accumulate display items that are painted!");
 
   FLB_LOG_PAINTED_LAYER_DECISION(
       this, "Accumulating dp=%s(%p), f=%p against pld=%p\n", aItem->Name(),
       aItem, aItem->Frame(), this);
 
   const bool hasOpacity = aOpacityIndices.Length() > 0;
+  UpdateEffectStatus(aType, aOpacityIndices);
 
   const DisplayItemClip* oldClip = mItemClip;
   mItemClip = &aClip;
 
-  UpdateEffectStatus(aType, aOpacityIndices);
-
   const bool isMerged = aItem->AsDisplayWrapList() &&
                         aItem->AsDisplayWrapList()->HasMergedFrames();
 
   if (IsEffectEndMarker(aType)) {
     mAssignedDisplayItems.emplace_back(aItem, aLayerState, nullptr,
                                        aContentRect, aType, hasOpacity,
                                        aTransform, isMerged);
     return;
@@ -4517,19 +4512,19 @@ void ContainerState::ProcessDisplayItems
       continue;
     }
 
     if (inEffect && marker == DisplayItemEntryType::Item) {
       // Fast-path for items inside flattened inactive layers. This works
       // because the layer state of the item cannot be active, otherwise the
       // parent item would not have been flattened.
       MOZ_ASSERT(selectedLayer);
-      selectedLayer->Accumulate(this, item, nsIntRect(), nsRect(), itemClip,
-                                layerState, aList, marker, opacityIndices,
-                                transformNode);
+      selectedLayer->Accumulate(this, item->AsPaintedDisplayItem(), nsIntRect(),
+                                nsRect(), itemClip, layerState, aList, marker,
+                                opacityIndices, transformNode);
       continue;
     }
 
     // Items outside of flattened effects and non-item markers inside flattened
     // effects are processed here.
     MOZ_ASSERT(!inEffect || (marker != DisplayItemEntryType::Item));
 
     if (itemAGR == lastAnimatedGeometryRoot) {
@@ -4982,17 +4977,19 @@ void ContainerState::ProcessDisplayItems
 
       /**
        * No need to allocate geometry for items that aren't
        * part of a PaintedLayer.
        */
       if (ownLayer->Manager() == mLayerBuilder->GetRetainingLayerManager()) {
         oldData = mLayerBuilder->GetOldLayerForFrame(item->Frame(),
                                                      item->GetPerFrameKey());
-        mLayerBuilder->StoreDataForFrame(item, ownLayer, layerState, oldData);
+
+        mLayerBuilder->StoreDataForFrame(item->AsPaintedDisplayItem(), ownLayer,
+                                         layerState, oldData);
       }
     } else {
       const bool backfaceHidden = item->In3DContextAndBackfaceIsHidden();
 
       // When container item hit test info is processed, we need to use the same
       // reference frame as the container children.
       const nsIFrame* referenceFrame = item == mContainerItem
                                            ? mContainerReferenceFrame
@@ -5013,19 +5010,19 @@ void ContainerState::ProcessDisplayItems
             });
       }
       MOZ_ASSERT(paintedLayerData);
 
       if (marker == DisplayItemEntryType::HitTestInfo) {
         MOZ_ASSERT(!transformNode);
         paintedLayerData->AccumulateHitTestItem(this, item, itemClip, nullptr);
       } else {
-        paintedLayerData->Accumulate(this, item, itemVisibleRect, itemContent,
-                                     itemClip, layerState, aList, marker,
-                                     opacityIndices, transformNode);
+        paintedLayerData->Accumulate(
+            this, item->AsPaintedDisplayItem(), itemVisibleRect, itemContent,
+            itemClip, layerState, aList, marker, opacityIndices, transformNode);
 
         if (!paintedLayerData->mLayer) {
           // Try to recycle the old layer of this display item.
           RefPtr<PaintedLayer> layer = AttemptToRecyclePaintedLayer(
               itemAGR, item, topLeft,
               inEffect ? containerReferenceFrame : referenceFrame);
           if (layer) {
             paintedLayerData->mLayer = layer;
@@ -5449,20 +5446,21 @@ void FrameLayerBuilder::AddPaintedDispla
 
       InvalidatePostTransformRegion(layer, invalid,
                                     GetTranslationForPaintedLayer(layer));
     }
   }
   aItem.mInactiveLayerManager = tempManager;
 }
 
-DisplayItemData* FrameLayerBuilder::StoreDataForFrame(nsDisplayItem* aItem,
-                                                      Layer* aLayer,
-                                                      LayerState aState,
-                                                      DisplayItemData* aData) {
+DisplayItemData* FrameLayerBuilder::StoreDataForFrame(
+    nsPaintedDisplayItem* aItem, Layer* aLayer, LayerState aState,
+    DisplayItemData* aData) {
+  MOZ_ASSERT(aItem);
+
   if (aData) {
     if (!aData->mUsed) {
       aData->BeginUpdate(aLayer, aState, false, aItem);
     }
     return aData;
   }
 
   LayerManagerData* lmd = static_cast<LayerManagerData*>(
@@ -5493,30 +5491,29 @@ void FrameLayerBuilder::StoreDataForFram
       DisplayItemData(lmd, aDisplayItemKey, aLayer, aFrame);
 
   data->BeginUpdate(aLayer, aState, true);
 
   lmd->mDisplayItems.push_back(data);
 }
 
 AssignedDisplayItem::AssignedDisplayItem(
-    nsDisplayItem* aItem, LayerState aLayerState, DisplayItemData* aData,
+    nsPaintedDisplayItem* aItem, LayerState aLayerState, DisplayItemData* aData,
     const nsRect& aContentRect, DisplayItemEntryType aType,
     const bool aHasOpacity, const RefPtr<TransformClipNode>& aTransform,
     const bool aIsMerged)
     : mItem(aItem),
+      mDisplayItemData(aData),
+      mTransform(aTransform),
+      mContentRect(aContentRect),
       mLayerState(aLayerState),
-      mDisplayItemData(aData),
-      mContentRect(aContentRect),
-      mTransform(aTransform),
       mType(aType),
       mReused(aItem->IsReused()),
       mMerged(aIsMerged),
       mHasOpacity(aHasOpacity),
-      mHasTransform(aTransform),
       mHasPaintRect(aItem->HasPaintRect()) {}
 
 AssignedDisplayItem::~AssignedDisplayItem() {
   if (mInactiveLayerManager) {
     mInactiveLayerManager->SetUserData(&gLayerManagerLayerBuilder, nullptr);
   }
 }
 
@@ -6247,20 +6244,22 @@ already_AddRefed<ContainerLayer> FrameLa
           this, aBuilder, aContainerFrame, aContainerItem,
           bounds.Intersect(childrenVisible), aTransform, aParameters,
           containerLayer, scaleParameters)) {
     return nullptr;
   }
 
   if (mRetainingManager) {
     if (aContainerItem) {
+      nsPaintedDisplayItem* item = aContainerItem->AsPaintedDisplayItem();
+      MOZ_ASSERT(item, "Only painted display items should build layers");
+
       DisplayItemData* data =
-          GetDisplayItemDataForManager(aContainerItem, mRetainingManager);
-      StoreDataForFrame(aContainerItem, containerLayer,
-                        LayerState::LAYER_ACTIVE, data);
+          GetDisplayItemDataForManager(item, mRetainingManager);
+      StoreDataForFrame(item, containerLayer, LayerState::LAYER_ACTIVE, data);
     } else {
       StoreDataForFrame(aContainerFrame, containerDisplayItemKey,
                         containerLayer, LayerState::LAYER_ACTIVE);
     }
   }
 
   nsIntRect pixBounds;
   nscoord appUnitsPerDevPixel;
@@ -6518,44 +6517,43 @@ static void DebugPaintItem(DrawTarget& a
 #endif
 
 /* static */
 void FrameLayerBuilder::RecomputeVisibilityForItems(
     std::vector<AssignedDisplayItem>& aItems, nsDisplayListBuilder* aBuilder,
     const nsIntRegion& aRegionToDraw, nsRect& aPreviousRectToDraw,
     const nsIntPoint& aOffset, int32_t aAppUnitsPerDevPixel, float aXScale,
     float aYScale) {
-  uint32_t i;
   // Update visible regions. We perform visibility analysis to take account
   // of occlusion culling.
   nsRegion visible = aRegionToDraw.ToAppUnits(aAppUnitsPerDevPixel);
   visible.MoveBy(NSIntPixelsToAppUnits(aOffset.x, aAppUnitsPerDevPixel),
                  NSIntPixelsToAppUnits(aOffset.y, aAppUnitsPerDevPixel));
   visible.ScaleInverseRoundOut(aXScale, aYScale);
 
   // We're going to read from previousRectToDraw for every iteration, let's do
   // that on the stack, and just update the heap allocated one now. By the end
   // of this function {visible} will have been modified by occlusion culling.
   nsRect previousRectToDraw = aPreviousRectToDraw;
   aPreviousRectToDraw = visible.GetBounds();
 
-  for (i = aItems.size(); i > 0; --i) {
+  for (uint32_t i = aItems.size(); i > 0; --i) {
     AssignedDisplayItem* cdi = &aItems[i - 1];
     if (!cdi->mItem) {
       continue;
     }
 
     if (cdi->mHasPaintRect &&
         !cdi->mContentRect.Intersects(visible.GetBounds()) &&
         !cdi->mContentRect.Intersects(previousRectToDraw)) {
       continue;
     }
 
-    if (IsEffectEndMarker(cdi->mType) || cdi->mHasOpacity ||
-        cdi->mHasTransform) {
+    if (IsEffectEndMarker(cdi->mType) || cdi->HasOpacity() ||
+        cdi->HasTransform()) {
       // The visibility calculations are skipped when the item is an effect end
       // marker, or when the display item is within a flattened effect group.
       // This is because RecomputeVisibility has already been called for the
       // group item, and all the children.
       continue;
     }
 
     const DisplayItemClip& clip = cdi->mItem->GetClip();
@@ -6946,20 +6944,20 @@ void FrameLayerBuilder::PaintItems(std::
 #ifdef MOZ_DUMP_PAINTING
     AUTO_PROFILER_LABEL_DYNAMIC_CSTR("FrameLayerBuilder::PaintItems",
                                      GRAPHICS_Rasterization, item->Name());
 #else
     AUTO_PROFILER_LABEL("FrameLayerBuilder::PaintItems",
                         GRAPHICS_Rasterization);
 #endif
 
-    MOZ_ASSERT((opacityLevel == 0 && !cdi.mHasOpacity) ||
-               (opacityLevel > 0 && cdi.mHasOpacity) ||
-               (transformLevel == 0 && !cdi.mHasTransform) ||
-               (transformLevel > 0 && cdi.mHasTransform));
+    MOZ_ASSERT((opacityLevel == 0 && !cdi.HasOpacity()) ||
+               (opacityLevel > 0 && cdi.HasOpacity()) ||
+               (transformLevel == 0 && !cdi.HasTransform()) ||
+               (transformLevel > 0 && cdi.HasTransform()));
 
     if (cdi.mType != DisplayItemEntryType::Item) {
       // If we are processing an effect marker, remove the current item clip, if
       // there is one.
       itemClipTracker.Restore();
     }
 
     if (cdi.mType == DisplayItemEntryType::PushOpacity ||
--- a/layout/painting/FrameLayerBuilder.h
+++ b/layout/painting/FrameLayerBuilder.h
@@ -21,16 +21,17 @@
 #include "Layers.h"
 #include "LayerUserData.h"
 #include "nsDisplayItemTypes.h"
 #include "TransformClipNode.h"
 
 class nsDisplayListBuilder;
 class nsDisplayList;
 class nsDisplayItem;
+class nsPaintedDisplayItem;
 class gfxContext;
 class nsDisplayItemGeometry;
 class nsDisplayMasksAndClipPaths;
 
 namespace mozilla {
 struct ActiveScrolledRoot;
 struct DisplayItemClipChain;
 namespace layers {
@@ -42,17 +43,17 @@ class ImageLayer;
 }  // namespace layers
 
 class FrameLayerBuilder;
 class LayerManagerData;
 class PaintedLayerData;
 class ContainerState;
 class PaintedDisplayItemLayerUserData;
 
-enum class DisplayItemEntryType {
+enum class DisplayItemEntryType : uint8_t {
   Item,
   PushOpacity,
   PushOpacityWithBg,
   PopOpacity,
   PushTransform,
   PopTransform,
   HitTestInfo,
 };
@@ -80,18 +81,18 @@ class DisplayItemData final {
   friend class ContainerState;
 
   uint32_t GetDisplayItemKey() { return mDisplayItemKey; }
   layers::Layer* GetLayer() const { return mLayer; }
   nsDisplayItemGeometry* GetGeometry() const { return mGeometry.get(); }
   const DisplayItemClip& GetClip() const { return mClip; }
   void Invalidate() { mIsInvalid = true; }
   void ClearAnimationCompositorState();
-  void SetItem(nsDisplayItem* aItem) { mItem = aItem; }
-  nsDisplayItem* GetItem() const { return mItem; }
+  void SetItem(nsPaintedDisplayItem* aItem) { mItem = aItem; }
+  nsPaintedDisplayItem* GetItem() const { return mItem; }
   nsIFrame* FirstFrame() const { return mFrameList[0]; }
 
   bool HasMergedFrames() const { return mFrameList.Length() > 1; }
 
   static DisplayItemData* AssertDisplayItemData(DisplayItemData* aData);
 
   void* operator new(size_t sz, nsPresContext* aPresContext) {
     // Check the recycle list first.
@@ -100,27 +101,27 @@ class DisplayItemData final {
   }
 
   nsrefcnt AddRef() {
     if (mRefCnt == UINT32_MAX) {
       NS_WARNING("refcount overflow, leaking object");
       return mRefCnt;
     }
     ++mRefCnt;
-    NS_LOG_ADDREF(this, mRefCnt, "ComputedStyle", sizeof(ComputedStyle));
+    NS_LOG_ADDREF(this, mRefCnt, "DisplayItemData", sizeof(DisplayItemData));
     return mRefCnt;
   }
 
   nsrefcnt Release() {
     if (mRefCnt == UINT32_MAX) {
       NS_WARNING("refcount overflow, leaking object");
       return mRefCnt;
     }
     --mRefCnt;
-    NS_LOG_RELEASE(this, mRefCnt, "ComputedStyle");
+    NS_LOG_RELEASE(this, mRefCnt, "DisplayItemData");
     if (mRefCnt == 0) {
       Destroy();
       return 0;
     }
     return mRefCnt;
   }
 
   RefPtr<TransformClipNode> mTransform;
@@ -162,19 +163,19 @@ class DisplayItemData final {
    * allocating a new object. Set the passed in parameters, and clears the opt
    * layer and inactive manager. Parent, and display item key are assumed to be
    * the same.
    *
    * EndUpdate must be called before the end of the transaction to complete the
    * update.
    */
   void BeginUpdate(layers::Layer* aLayer, LayerState aState, bool aFirstUpdate,
-                   nsDisplayItem* aItem = nullptr);
+                   nsPaintedDisplayItem* aItem = nullptr);
   void BeginUpdate(layers::Layer* aLayer, LayerState aState,
-                   nsDisplayItem* aItem, bool aIsReused, bool aIsMerged);
+                   nsPaintedDisplayItem* aItem, bool aIsReused, bool aIsMerged);
 
   /**
    * Completes the update of this, and removes any references to data that won't
    * live longer than the transaction.
    *
    * Updates the geometry, frame list and clip.
    * For items within a PaintedLayer, a geometry object must be specified to
    * retain until the next transaction.
@@ -193,17 +194,17 @@ class DisplayItemData final {
   DisplayItemClip mClip;
   uint32_t mDisplayItemKey;
   LayerState mLayerState;
 
   /**
    * Temporary stoarage of the display item being referenced, only valid between
    * BeginUpdate and EndUpdate.
    */
-  nsDisplayItem* mItem;
+  nsPaintedDisplayItem* mItem;
   nsRegion mChangedFrameInvalidations;
 
   /**
    * Used to track if data currently stored in mFramesWithLayers (from an
    * existing paint) has been updated in the current paint.
    */
   bool mUsed;
   bool mIsInvalid;
@@ -218,41 +219,45 @@ class RefCountedRegion {
   NS_INLINE_DECL_REFCOUNTING(RefCountedRegion)
 
   RefCountedRegion() : mIsInfinite(false) {}
   nsRegion mRegion;
   bool mIsInfinite;
 };
 
 struct AssignedDisplayItem {
-  AssignedDisplayItem(nsDisplayItem* aItem, LayerState aLayerState,
+  AssignedDisplayItem(nsPaintedDisplayItem* aItem, LayerState aLayerState,
                       DisplayItemData* aData, const nsRect& aContentRect,
                       DisplayItemEntryType aType, const bool aHasOpacity,
                       const RefPtr<TransformClipNode>& aTransform,
                       const bool aIsMerged);
   ~AssignedDisplayItem();
 
-  nsDisplayItem* mItem;
-  LayerState mLayerState;
+  bool HasOpacity() const { return mHasOpacity; }
+
+  bool HasTransform() const { return mTransform; }
+
+  nsPaintedDisplayItem* mItem;
   DisplayItemData* mDisplayItemData;
-  nsRect mContentRect;
 
   /**
    * If the display item is being rendered as an inactive
    * layer, then this stores the layer manager being
    * used for the inactive transaction.
    */
   RefPtr<layers::LayerManager> mInactiveLayerManager;
   RefPtr<TransformClipNode> mTransform;
+
+  nsRect mContentRect;
+  LayerState mLayerState;
   DisplayItemEntryType mType;
 
   bool mReused;
   bool mMerged;
   bool mHasOpacity;
-  bool mHasTransform;
   bool mHasPaintRect;
 };
 
 struct ContainerLayerParameters {
   ContainerLayerParameters()
       : mXScale(1),
         mYScale(1),
         mLayerContentsVisibleRect(nullptr),
@@ -628,17 +633,17 @@ class FrameLayerBuilder : public layers:
       nsIFrame* aFrame, uint32_t aDisplayItemKey,
       DisplayItemData* aOldData = nullptr,
       LayerManager* aOldLayerManager = nullptr);
 
   /**
    * Stores DisplayItemData associated with aFrame, stores the data in
    * mNewDisplayItemData.
    */
-  DisplayItemData* StoreDataForFrame(nsDisplayItem* aItem, Layer* aLayer,
+  DisplayItemData* StoreDataForFrame(nsPaintedDisplayItem* aItem, Layer* aLayer,
                                      LayerState aState, DisplayItemData* aData);
   void StoreDataForFrame(nsIFrame* aFrame, uint32_t aDisplayItemKey,
                          Layer* aLayer, LayerState aState);
 
  protected:
   friend class LayerManagerData;
 
   // Flash the area within the context clip if paint flashing is enabled.
@@ -649,29 +654,21 @@ class FrameLayerBuilder : public layers:
    * doesn't exist.
    *
    * Note that the pointer returned here is only valid so long as you don't
    * poke the LayerManagerData's mFramesWithLayers hashtable.
    */
   DisplayItemData* GetDisplayItemData(nsIFrame* aFrame, uint32_t aKey);
 
   /*
-   * Get the DisplayItemData associated with this frame / display item pair,
+   * Get the DisplayItemData associated with this display item,
    * using the LayerManager instead of FrameLayerBuilder.
    */
-  static DisplayItemData* GetDisplayItemDataForManager(nsIFrame* aFrame,
-                                                       uint32_t aDisplayItemKey,
-                                                       LayerManager* aManager);
   static DisplayItemData* GetDisplayItemDataForManager(
-      nsIFrame* aFrame, uint32_t aDisplayItemKey);
-  static DisplayItemData* GetDisplayItemDataForManager(nsDisplayItem* aItem,
-                                                       LayerManager* aManager);
-  static DisplayItemData* GetDisplayItemDataForManager(nsIFrame* aFrame,
-                                                       uint32_t aDisplayItemKey,
-                                                       LayerManagerData* aData);
+      nsPaintedDisplayItem* aItem, LayerManager* aManager);
 
   /**
    * We store one of these for each display item associated with a
    * PaintedLayer, in a hashtable that maps each PaintedLayer to an array
    * of ClippedDisplayItems. (PaintedLayerItemsEntry is the hash entry
    * for that hashtable.)
    * These are only stored during the paint process, so that the
    * DrawPaintedLayer callback can figure out which items to draw for the
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -146,16 +146,29 @@ void AssertUniqueItem(nsDisplayItem* aIt
 #endif
 
 bool ShouldBuildItemForEventsOrPlugins(const DisplayItemType aType) {
   return aType == DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO ||
          aType == DisplayItemType::TYPE_PLUGIN ||
          (GetDisplayItemFlagsForType(aType) & TYPE_IS_CONTAINER);
 }
 
+void UpdateDisplayItemData(nsPaintedDisplayItem* aItem) {
+  for (mozilla::DisplayItemData* did : aItem->Frame()->DisplayItemData()) {
+    if (did->GetDisplayItemKey() == aItem->GetPerFrameKey() &&
+        did->GetLayer()->AsPaintedLayer()) {
+      if (!did->HasMergedFrames()) {
+        aItem->SetDisplayItemData(did, did->GetLayer()->Manager());
+      }
+
+      return;
+    }
+  }
+}
+
 /* static */
 bool ActiveScrolledRoot::IsAncestor(const ActiveScrolledRoot* aAncestor,
                                     const ActiveScrolledRoot* aDescendant) {
   if (!aAncestor) {
     // nullptr is the root
     return true;
   }
   if (Depth(aAncestor) > Depth(aDescendant)) {
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -1984,16 +1984,17 @@ class nsDisplayListBuilder {
   bool mBuildAsyncZoomContainer;
 
   nsRect mHitTestArea;
   CompositorHitTestInfo mHitTestInfo;
 };
 
 class nsDisplayItem;
 class nsDisplayItemBase;
+class nsPaintedDisplayItem;
 class nsDisplayList;
 class RetainedDisplayList;
 
 // All types are defined in nsDisplayItemTypes.h
 #define NS_DISPLAY_DECL_NAME(n, e)                                           \
   const char* Name() const override { return n; }                            \
   constexpr static DisplayItemType ItemType() { return DisplayItemType::e; } \
                                                                              \
@@ -2029,16 +2030,18 @@ void AssertUniqueItem(nsDisplayItem* aIt
 #endif
 
 /**
  * Returns true, if a display item of given |aType| needs to be built within
  * opacity:0 container.
  */
 bool ShouldBuildItemForEventsOrPlugins(const DisplayItemType aType);
 
+void UpdateDisplayItemData(nsPaintedDisplayItem* aItem);
+
 template <typename T, typename F, typename... Args>
 MOZ_ALWAYS_INLINE T* MakeDisplayItem(nsDisplayListBuilder* aBuilder, F* aFrame,
                                      Args&&... aArgs) {
   static_assert(std::is_base_of<nsDisplayItem, T>::value,
                 "Display item should be derived from nsDisplayItem");
   static_assert(std::is_base_of<nsIFrame, F>::value,
                 "Frame type should be derived from nsIFrame");
 
@@ -2052,28 +2055,19 @@ MOZ_ALWAYS_INLINE T* MakeDisplayItem(nsD
   T* item = new (aBuilder) T(aBuilder, aFrame, std::forward<Args>(aArgs)...);
 
   if (type != DisplayItemType::TYPE_GENERIC) {
     item->SetType(type);
   }
 
   item->SetPerFrameKey(item->CalculatePerFrameKey());
 
-  const mozilla::SmallPointerArray<mozilla::DisplayItemData>& array =
-      item->Frame()->DisplayItemData();
-  for (uint32_t i = 0; i < array.Length(); i++) {
-    mozilla::DisplayItemData* did = array.ElementAt(i);
-    if (did->GetDisplayItemKey() == item->GetPerFrameKey()) {
-      if (did->GetLayer()->AsPaintedLayer()) {
-        if (!did->HasMergedFrames()) {
-          item->SetDisplayItemData(did, did->GetLayer()->Manager());
-        }
-        break;
-      }
-    }
+  nsPaintedDisplayItem* paintedItem = item->AsPaintedDisplayItem();
+  if (paintedItem) {
+    UpdateDisplayItemData(paintedItem);
   }
 
   if (aBuilder->InInvalidSubtree() ||
       item->FrameForInvalidation()->IsFrameModified()) {
     item->SetModifiedFrame(true);
   }
 
 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
@@ -2423,20 +2417,17 @@ class nsDisplayItem : public nsDisplayIt
 
  protected:
   // This is never instantiated directly (it has pure virtual methods), so no
   // need to count constructors and destructors.
   nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame);
   nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                 const ActiveScrolledRoot* aActiveScrolledRoot);
 
-  virtual ~nsDisplayItem() {
-    MOZ_COUNT_DTOR(nsDisplayItem);
-    SetDisplayItemData(nullptr, nullptr);
-  }
+  virtual ~nsDisplayItem() { MOZ_COUNT_DTOR(nsDisplayItem); }
 
   /**
    * The custom copy-constructor is implemented to prevent copying the saved
    * state of the item.
    * This is currently only used when creating temporary items for merging.
    */
   nsDisplayItem(nsDisplayListBuilder* aBuilder, const nsDisplayItem& aOther)
       : nsDisplayItemBase(aBuilder, aOther),
@@ -2999,38 +2990,16 @@ class nsDisplayItem : public nsDisplayIt
     return mFrame->GetContent() == aOther->Frame()->GetContent();
   }
 
   virtual void NotifyUsed(nsDisplayListBuilder* aBuilder) {}
 
   virtual mozilla::Maybe<nsRect> GetClipWithRespectToASR(
       nsDisplayListBuilder* aBuilder, const ActiveScrolledRoot* aASR) const;
 
-  void SetDisplayItemData(mozilla::DisplayItemData* aDID,
-                          mozilla::layers::LayerManager* aLayerManager) {
-    if (mDisplayItemData) {
-      MOZ_ASSERT(!mDisplayItemData->GetItem() ||
-                 mDisplayItemData->GetItem() == this);
-      mDisplayItemData->SetItem(nullptr);
-    }
-    if (aDID) {
-      if (aDID->GetItem()) {
-        aDID->GetItem()->SetDisplayItemData(nullptr, nullptr);
-      }
-      aDID->SetItem(this);
-    }
-    mDisplayItemData = aDID;
-    mDisplayItemDataLayerManager = aLayerManager;
-  }
-
-  mozilla::DisplayItemData* GetDisplayItemData() { return mDisplayItemData; }
-  mozilla::layers::LayerManager* GetDisplayItemDataLayerManager() {
-    return mDisplayItemDataLayerManager;
-  }
-
   const nsRect& GetPaintRect() const { return mPaintRect; }
 
   virtual const nsRect& GetUntransformedPaintRect() const {
     return GetPaintRect();
   }
 
   virtual bool HasHitTestInfo() const { return false; }
 
@@ -3044,18 +3013,16 @@ class nsDisplayItem : public nsDisplayIt
   bool CanUseAdvancedLayer(LayerManager* aManager) const;
 
   RefPtr<const DisplayItemClipChain> mClipChain;
   const DisplayItemClip* mClip;
   RefPtr<const ActiveScrolledRoot> mActiveScrolledRoot;
   // Result of FindReferenceFrameFor(mFrame), if mFrame is non-null
   const nsIFrame* mReferenceFrame;
   RefPtr<struct AnimatedGeometryRoot> mAnimatedGeometryRoot;
-  mozilla::DisplayItemData* mDisplayItemData = nullptr;
-  mozilla::layers::LayerManager* mDisplayItemDataLayerManager = nullptr;
 
   struct {
     RefPtr<const DisplayItemClipChain> mClipChain;
     const DisplayItemClip* mClip;
   } mState;
 
   // Result of ToReferenceFrame(mFrame), if mFrame is non-null
   nsPoint mToReferenceFrame;
@@ -3088,16 +3055,40 @@ class nsDisplayItem : public nsDisplayIt
 
 class nsPaintedDisplayItem : public nsDisplayItem {
  public:
   nsPaintedDisplayItem* AsPaintedDisplayItem() final { return this; }
   const nsPaintedDisplayItem* AsPaintedDisplayItem() const final {
     return this;
   }
 
+  ~nsPaintedDisplayItem() override { SetDisplayItemData(nullptr, nullptr); }
+
+  void SetDisplayItemData(mozilla::DisplayItemData* aDID,
+                          mozilla::layers::LayerManager* aLayerManager) {
+    if (mDisplayItemData) {
+      MOZ_ASSERT(!mDisplayItemData->GetItem() ||
+                 mDisplayItemData->GetItem() == this);
+      mDisplayItemData->SetItem(nullptr);
+    }
+    if (aDID) {
+      if (aDID->GetItem()) {
+        aDID->GetItem()->SetDisplayItemData(nullptr, nullptr);
+      }
+      aDID->SetItem(this);
+    }
+    mDisplayItemData = aDID;
+    mDisplayItemDataLayerManager = aLayerManager;
+  }
+
+  mozilla::DisplayItemData* GetDisplayItemData() { return mDisplayItemData; }
+  mozilla::layers::LayerManager* GetDisplayItemDataLayerManager() {
+    return mDisplayItemDataLayerManager;
+  }
+
   /**
    * Stores the given opacity value to be applied when drawing. It is an error
    * to call this if CanApplyOpacity returned false.
    */
   virtual void ApplyOpacity(nsDisplayListBuilder* aBuilder, float aOpacity,
                             const DisplayItemClipChain* aClip) {
     MOZ_ASSERT(CanApplyOpacity(), "ApplyOpacity is not supported on this type");
   }
@@ -3158,16 +3149,20 @@ class nsPaintedDisplayItem : public nsDi
 
   nsPaintedDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                        const ActiveScrolledRoot* aActiveScrolledRoot)
       : nsDisplayItem(aBuilder, aFrame, aActiveScrolledRoot) {}
 
   nsPaintedDisplayItem(nsDisplayListBuilder* aBuilder,
                        const nsPaintedDisplayItem& aOther)
       : nsDisplayItem(aBuilder, aOther) {}
+
+ private:
+  mozilla::DisplayItemData* mDisplayItemData = nullptr;
+  mozilla::layers::LayerManager* mDisplayItemDataLayerManager = nullptr;
 };
 
 /**
  * Manages a singly-linked list of display list items.
  *
  * mSentinel is the sentinel list value, the first value in the null-terminated
  * linked list of items. mTop is the last item in the list (whose 'above'
  * pointer is null). This class has no virtual methods. So list objects are just