Bug 1540785 - Part 1: Introduce nsDisplayItemBase r=mattwoodrow
authorMiko Mynttinen <mikokm@gmail.com>
Mon, 22 Apr 2019 19:57:59 +0000
changeset 529218 5f7f77eac50e0fe1082411aa5c566714281fdbd4
parent 529217 127af2f6e16df6f091fa45f636115ce7ada68b34
child 529219 7c58a86df1c6aa72126951ba9b2930a6ce5de99e
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1540785
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 1540785 - Part 1: Introduce nsDisplayItemBase r=mattwoodrow *** Differential Revision: https://phabricator.services.mozilla.com/D27579
dom/animation/EffectCompositor.h
dom/animation/EffectSet.h
layout/generic/nsFrame.cpp
layout/generic/nsIFrame.h
layout/generic/nsSubDocumentFrame.cpp
layout/ipc/RenderFrame.h
layout/painting/FrameLayerBuilder.cpp
layout/painting/RetainedDisplayListBuilder.cpp
layout/painting/nsDisplayItemTypes.h
layout/painting/nsDisplayList.cpp
layout/painting/nsDisplayList.h
--- a/dom/animation/EffectCompositor.h
+++ b/dom/animation/EffectCompositor.h
@@ -18,17 +18,17 @@
 #include "nsCycleCollectionParticipant.h"
 #include "nsDataHashtable.h"
 #include "nsTArray.h"
 
 class nsCSSPropertyIDSet;
 class nsAtom;
 class nsIFrame;
 class nsPresContext;
-enum class DisplayItemType : uint32_t;
+enum class DisplayItemType : uint8_t;
 struct RawServoAnimationValueMap;
 
 namespace mozilla {
 
 class ComputedStyle;
 class EffectSet;
 class RestyleTracker;
 class StyleAnimationValue;
--- a/dom/animation/EffectSet.h
+++ b/dom/animation/EffectSet.h
@@ -11,17 +11,17 @@
 #include "mozilla/EffectCompositor.h"
 #include "mozilla/EnumeratedArray.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/dom/KeyframeEffect.h"
 #include "nsHashKeys.h"    // For nsPtrHashKey
 #include "nsTHashtable.h"  // For nsTHashtable
 
 class nsPresContext;
-enum class DisplayItemType : uint32_t;
+enum class DisplayItemType : uint8_t;
 
 namespace mozilla {
 
 namespace dom {
 class Element;
 }  // namespace dom
 
 enum class PseudoStyleType : uint8_t;
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -925,72 +925,72 @@ static void AddAndRemoveImageAssociation
     });
   }
 
   CompareLayers(aNewLayers, aOldLayers, [&](imgRequestProxy* aReq) {
     aImageLoader.AssociateRequestToFrame(aReq, aFrame, 0);
   });
 }
 
-void nsIFrame::AddDisplayItem(nsDisplayItem* aItem) {
+void nsIFrame::AddDisplayItem(nsDisplayItemBase* aItem) {
   DisplayItemArray* items = GetProperty(DisplayItems());
   if (!items) {
     items = new DisplayItemArray();
     AddProperty(DisplayItems(), items);
   }
   MOZ_DIAGNOSTIC_ASSERT(!items->Contains(aItem));
   items->AppendElement(aItem);
 }
 
-bool nsIFrame::RemoveDisplayItem(nsDisplayItem* aItem) {
+bool nsIFrame::RemoveDisplayItem(nsDisplayItemBase* aItem) {
   DisplayItemArray* items = GetProperty(DisplayItems());
   if (!items) {
     return false;
   }
   bool result = items->RemoveElement(aItem);
   if (items->IsEmpty()) {
     DeleteProperty(DisplayItems());
   }
   return result;
 }
 
 bool nsIFrame::HasDisplayItems() {
   DisplayItemArray* items = GetProperty(DisplayItems());
   return items != nullptr;
 }
 
-bool nsIFrame::HasDisplayItem(nsDisplayItem* aItem) {
+bool nsIFrame::HasDisplayItem(nsDisplayItemBase* aItem) {
   DisplayItemArray* items = GetProperty(DisplayItems());
   if (!items) {
     return false;
   }
   return items->Contains(aItem);
 }
 
 bool nsIFrame::HasDisplayItem(uint32_t aKey) {
   DisplayItemArray* items = GetProperty(DisplayItems());
   if (!items) {
     return false;
   }
 
-  for (nsDisplayItem* i : *items) {
+  for (nsDisplayItemBase* i : *items) {
     if (i->GetPerFrameKey() == aKey) {
       return true;
     }
   }
   return false;
 }
 
 void nsIFrame::DiscardOldItems() {
   DisplayItemArray* items = GetProperty(DisplayItems());
   if (!items) {
     return;
   }
 
-  for (nsDisplayItem* i : *items) {
+  for (nsDisplayItemBase* i : *items) {
     i->DiscardIfOldItem();
   }
 }
 
 void nsIFrame::RemoveDisplayItemDataForDeletion() {
   // Destroying a WebRenderUserDataTable can cause destruction of other objects
   // which can remove frame properties in their destructor. If we delete a frame
   // property it runs the destructor of the stored object in the middle of
@@ -1007,17 +1007,17 @@ void nsIFrame::RemoveDisplayItemDataForD
     delete userDataTable;
   }
 
   FrameLayerBuilder::RemoveFrameFromLayerManager(this, DisplayItemData());
   DisplayItemData().Clear();
 
   DisplayItemArray* items = RemoveProperty(DisplayItems());
   if (items) {
-    for (nsDisplayItem* i : *items) {
+    for (nsDisplayItemBase* i : *items) {
       if (i->GetDependentFrame() == this && !i->HasDeletedFrame()) {
         i->Frame()->MarkNeedsDisplayItemRebuild();
       }
       i->RemoveFrame(this);
     }
     delete items;
   }
 
@@ -1096,17 +1096,17 @@ void nsIFrame::MarkNeedsDisplayItemRebui
 
   MOZ_ASSERT(
       PresContext()->LayoutPhaseCount(eLayoutPhase_DisplayListBuilding) == 0);
 
   // Hopefully this is cheap, but we could use a frame state bit to note
   // the presence of dependencies to speed it up.
   DisplayItemArray* items = GetProperty(DisplayItems());
   if (items) {
-    for (nsDisplayItem* i : *items) {
+    for (nsDisplayItemBase* i : *items) {
       if (i->HasDeletedFrame() || i->Frame() == this) {
         // Ignore the items with deleted frames, and the items with |this| as
         // the primary frame.
         continue;
       }
 
       if (i->GetDependentFrame() == this) {
         // For items with |this| as a dependent frame, mark the primary frame
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -98,17 +98,17 @@
 class nsAtom;
 class nsPresContext;
 class nsView;
 class nsIWidget;
 class nsISelectionController;
 class nsBoxLayoutState;
 class nsBoxLayout;
 class nsILineIterator;
-class nsDisplayItem;
+class nsDisplayItemBase;
 class nsDisplayListBuilder;
 class nsDisplayListSet;
 class nsDisplayList;
 class gfxSkipChars;
 class gfxSkipCharsIterator;
 class gfxContext;
 class nsLineList_iterator;
 class nsAbsoluteContainingBlock;
@@ -1149,17 +1149,17 @@ class nsIFrame : public nsQueryFrame {
   }
 
   virtual nsPoint GetPositionOfChildIgnoringScrolling(const nsIFrame* aChild) {
     return aChild->GetPosition();
   }
 
   nsPoint GetPositionIgnoringScrolling() const;
 
-  typedef AutoTArray<nsDisplayItem*, 4> DisplayItemArray;
+  typedef AutoTArray<nsDisplayItemBase*, 4> DisplayItemArray;
 
 #define NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(prop, type, dtor)              \
   static const mozilla::FramePropertyDescriptor<type>* prop() {            \
     /* Use of constexpr caused startup crashes with MSVC2015u1 PGO. */     \
     static const auto descriptor =                                         \
         mozilla::FramePropertyDescriptor<type>::NewWithDestructor<dtor>(); \
     return &descriptor;                                                    \
   }
@@ -4144,21 +4144,21 @@ class nsIFrame : public nsQueryFrame {
                              aSize.AsExtremumLength(), aFlags);
   }
 
   DisplayItemDataArray& DisplayItemData() { return mDisplayItemData; }
   const DisplayItemDataArray& DisplayItemData() const {
     return mDisplayItemData;
   }
 
-  void AddDisplayItem(nsDisplayItem* aItem);
-  bool RemoveDisplayItem(nsDisplayItem* aItem);
+  void AddDisplayItem(nsDisplayItemBase* aItem);
+  bool RemoveDisplayItem(nsDisplayItemBase* aItem);
   void RemoveDisplayItemDataForDeletion();
   bool HasDisplayItems();
-  bool HasDisplayItem(nsDisplayItem* aItem);
+  bool HasDisplayItem(nsDisplayItemBase* aItem);
   bool HasDisplayItem(uint32_t aKey);
   void DiscardOldItems();
 
   bool ForceDescendIntoIfVisible() const { return mForceDescendIntoIfVisible; }
   void SetForceDescendIntoIfVisible(bool aForce) {
     mForceDescendIntoIfVisible = aForce;
   }
 
--- a/layout/generic/nsSubDocumentFrame.cpp
+++ b/layout/generic/nsSubDocumentFrame.cpp
@@ -1202,20 +1202,21 @@ void nsSubDocumentFrame::ClearDisplayIte
 
   nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(this);
   MOZ_ASSERT(displayRoot);
 
   RetainedDisplayListBuilder* retainedBuilder =
       displayRoot->GetProperty(RetainedDisplayListBuilder::Cached());
   MOZ_ASSERT(retainedBuilder);
 
-  for (nsDisplayItem* i : *items) {
+  for (nsDisplayItemBase* i : *items) {
     if (i->GetType() == DisplayItemType::TYPE_SUBDOCUMENT) {
-      i->GetChildren()->DeleteAll(retainedBuilder->Builder());
-      static_cast<nsDisplaySubDocument*>(i)->Disown();
+      auto* item = static_cast<nsDisplaySubDocument*>(i);
+      item->GetChildren()->DeleteAll(retainedBuilder->Builder());
+      item->Disown();
       break;
     }
   }
 }
 
 nsView* nsSubDocumentFrame::EnsureInnerView() {
   if (mInnerView) {
     return mInnerView;
--- a/layout/ipc/RenderFrame.h
+++ b/layout/ipc/RenderFrame.h
@@ -85,18 +85,16 @@ class RenderFrame final {
 }  // namespace layout
 }  // namespace mozilla
 
 /**
  * A nsDisplayRemote will graft a remote frame's shadow layer tree (for a given
  * nsFrameLoader) into its parent frame's layer tree.
  */
 class nsDisplayRemote final : public nsDisplayItem {
-  friend class nsDisplayItem;
-
   typedef mozilla::dom::TabId TabId;
   typedef mozilla::gfx::Matrix4x4 Matrix4x4;
   typedef mozilla::layers::EventRegionsOverride EventRegionsOverride;
   typedef mozilla::layers::Layer Layer;
   typedef mozilla::layers::LayersId LayersId;
   typedef mozilla::layers::RefLayer RefLayer;
   typedef mozilla::layout::RenderFrame RenderFrame;
   typedef mozilla::LayoutDeviceRect LayoutDeviceRect;
@@ -123,16 +121,17 @@ class nsDisplayRemote final : public nsD
       nsDisplayListBuilder* aDisplayListBuilder) override;
   bool UpdateScrollData(
       mozilla::layers::WebRenderScrollData* aData,
       mozilla::layers::WebRenderLayerScrollData* aLayerData) override;
 
   NS_DISPLAY_DECL_NAME("Remote", TYPE_REMOTE)
 
  private:
+  friend class nsDisplayItemBase;
   nsFrameLoader* GetFrameLoader() const;
 
   TabId mTabId;
   LayersId mLayersId;
   LayoutDeviceIntPoint mOffset;
   EventRegionsOverride mEventRegionsOverride;
 };
 
--- a/layout/painting/FrameLayerBuilder.cpp
+++ b/layout/painting/FrameLayerBuilder.cpp
@@ -373,17 +373,25 @@ DisplayItemData::~DisplayItemData() {
 
   if (sAliveDisplayItemDatas->Count() == 0) {
     delete sAliveDisplayItemDatas;
     sAliveDisplayItemDatas = nullptr;
   }
 }
 
 void DisplayItemData::ClearAnimationCompositorState() {
-  DisplayItemType type = static_cast<DisplayItemType>(mDisplayItemKey);
+  if (mDisplayItemKey > static_cast<uint8_t>(DisplayItemType::TYPE_MAX)) {
+    // This is sort of a hack. The display item key has higher bits set, which
+    // means that it is not the only display item for the frame.
+    // This branch skips separator transforms.
+    return;
+  }
+
+  const DisplayItemType type = GetDisplayItemTypeFromKey(mDisplayItemKey);
+
   // FIXME: Bug 1530857: Add background_color.
   if (type != DisplayItemType::TYPE_TRANSFORM &&
       type != DisplayItemType::TYPE_OPACITY) {
     return;
   }
 
   for (nsIFrame* frame : mFrameList) {
     EffectCompositor::ClearIsRunningOnCompositor(frame, type);
--- a/layout/painting/RetainedDisplayListBuilder.cpp
+++ b/layout/painting/RetainedDisplayListBuilder.cpp
@@ -473,17 +473,17 @@ class MergeState {
   }
 
   bool HasMatchingItemInOldList(nsDisplayItem* aItem, OldListIndex* aOutIndex) {
     nsIFrame::DisplayItemArray* items =
         aItem->Frame()->GetProperty(nsIFrame::DisplayItems());
     // Look for an item that matches aItem's frame and per-frame-key, but isn't
     // the same item.
     uint32_t outerKey = mOuterItem ? mOuterItem->GetPerFrameKey() : 0;
-    for (nsDisplayItem* i : *items) {
+    for (nsDisplayItemBase* i : *items) {
       if (i != aItem && i->Frame() == aItem->Frame() &&
           i->GetPerFrameKey() == aItem->GetPerFrameKey()) {
         if (i->GetOldListIndex(mOldList, outerKey, aOutIndex)) {
           return true;
         }
       }
     }
     return false;
@@ -504,17 +504,17 @@ class MergeState {
       Span<const MergedListIndex> aDirectPredecessors,
       const Maybe<MergedListIndex>& aExtraDirectPredecessor) {
     UpdateContainerASR(aItem);
     aItem->NotifyUsed(mBuilder->Builder());
 
 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
     nsIFrame::DisplayItemArray* items =
         aItem->Frame()->GetProperty(nsIFrame::DisplayItems());
-    for (nsDisplayItem* i : *items) {
+    for (nsDisplayItemBase* i : *items) {
       if (i->Frame() == aItem->Frame() &&
           i->GetPerFrameKey() == aItem->GetPerFrameKey()) {
         MOZ_DIAGNOSTIC_ASSERT(!i->IsMergedItem());
       }
     }
 
     aItem->SetMergedPreProcessed(true, false);
 #endif
@@ -792,19 +792,19 @@ static void GetModifiedAndFramesWithProp
 
 static nsDisplayItem* GetFirstDisplayItemWithChildren(nsIFrame* aFrame) {
   nsIFrame::DisplayItemArray* items =
       aFrame->GetProperty(nsIFrame::DisplayItems());
   if (!items) {
     return nullptr;
   }
 
-  for (nsDisplayItem* i : *items) {
-    if (i->GetChildren()) {
-      return i;
+  for (nsDisplayItemBase* i : *items) {
+    if (i->HasChildren()) {
+      return static_cast<nsDisplayItem*>(i);
     }
   }
   return nullptr;
 }
 
 static bool IsInPreserve3DContext(const nsIFrame* aFrame) {
   return aFrame->Extend3DContext() ||
          aFrame->Combines3DTransformWithAncestors();
--- a/layout/painting/nsDisplayItemTypes.h
+++ b/layout/painting/nsDisplayItemTypes.h
@@ -10,17 +10,17 @@
  * It's useful to be able to dynamically check the type of certain items.
  * Every subclass of nsDisplayItem must have a new type added here for the
  * purposes of easy comparison and matching of items in different display lists.
  */
 
 #ifndef NSDISPLAYITEMTYPES_H_
 #define NSDISPLAYITEMTYPES_H_
 
-enum class DisplayItemType : uint32_t {
+enum class DisplayItemType : uint8_t {
   TYPE_ZERO = 0, /** Spacer so that the first item starts at 1 */
 
 #define DECLARE_DISPLAY_ITEM_TYPE(name, flags) TYPE_##name,
 #include "nsDisplayItemTypesList.h"
 #undef DECLARE_DISPLAY_ITEM_TYPE
 
   TYPE_MAX
 };
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -128,17 +128,17 @@ static bool SpammyLayoutWarningsEnabled(
 
 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
 void AssertUniqueItem(nsDisplayItem* aItem) {
   nsIFrame::DisplayItemArray* items =
       aItem->Frame()->GetProperty(nsIFrame::DisplayItems());
   if (!items) {
     return;
   }
-  for (nsDisplayItem* i : *items) {
+  for (nsDisplayItemBase* i : *items) {
     if (i != aItem && !i->HasDeletedFrame() && i->Frame() == aItem->Frame() &&
         i->GetPerFrameKey() == aItem->GetPerFrameKey()) {
       if (i->IsPreProcessedItem()) {
         continue;
       }
       MOZ_DIAGNOSTIC_ASSERT(false, "Duplicate display item!");
     }
   }
@@ -3156,33 +3156,52 @@ struct ContentComparator {
                                               mCommonAncestor) < 0;
   }
 };
 
 void nsDisplayList::SortByContentOrder(nsIContent* aCommonAncestor) {
   Sort<nsDisplayItem*>(ContentComparator(aCommonAncestor));
 }
 
-#ifndef DEBUG
+bool nsDisplayItemBase::HasModifiedFrame() const {
+  return mItemFlags.contains(ItemBaseFlag::ModifiedFrame);
+}
+
+void nsDisplayItemBase::SetModifiedFrame(bool aModified) {
+  if (aModified) {
+    mItemFlags += ItemBaseFlag::ModifiedFrame;
+  } else {
+    mItemFlags -= ItemBaseFlag::ModifiedFrame;
+  }
+}
+
+void nsDisplayItemBase::SetDeletedFrame() {
+  mItemFlags += ItemBaseFlag::DeletedFrame;
+}
+
+bool nsDisplayItemBase::HasDeletedFrame() const {
+  return mItemFlags.contains(ItemBaseFlag::DeletedFrame) ||
+         (GetType() == DisplayItemType::TYPE_REMOTE &&
+          !static_cast<const nsDisplayRemote*>(this)->GetFrameLoader());
+}
+
+#if !defined(DEBUG) && !defined(MOZ_DIAGNOSTIC_ASSERT_ENABLED)
 static_assert(sizeof(nsDisplayItem) <= 176, "nsDisplayItem has grown");
 #endif
 
 nsDisplayItem::nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
     : nsDisplayItem(aBuilder, aFrame, aBuilder->CurrentActiveScrolledRoot()) {}
 
 nsDisplayItem::nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                              const ActiveScrolledRoot* aActiveScrolledRoot)
-    : mFrame(aFrame),
-      mItemFlags(),
+    : nsDisplayItemBase(aBuilder, aFrame),
       mActiveScrolledRoot(aActiveScrolledRoot),
       mAnimatedGeometryRoot(nullptr) {
   MOZ_COUNT_CTOR(nsDisplayItem);
-  if (aBuilder->IsRetainingDisplayList()) {
-    mFrame->AddDisplayItem(this);
-  }
+
   mReferenceFrame = aBuilder->FindReferenceFrameFor(aFrame, &mToReferenceFrame);
   // This can return the wrong result if the item override
   // ShouldFixToViewport(), the item needs to set it again in its constructor.
   mAnimatedGeometryRoot = aBuilder->FindAnimatedGeometryRootFor(aFrame);
   MOZ_ASSERT(nsLayoutUtils::IsAncestorFrameCrossDoc(
                  aBuilder->RootReferenceFrame(), *mAnimatedGeometryRoot),
              "Bad");
   NS_ASSERTION(
@@ -3215,34 +3234,16 @@ bool nsDisplayItem::ForceActiveLayers() 
   if (!sForceCached) {
     Preferences::AddBoolVarCache(&sForce, "layers.force-active", false);
     sForceCached = true;
   }
 
   return sForce;
 }
 
-bool nsDisplayItem::HasModifiedFrame() const {
-  return mItemFlags.contains(ItemFlag::ModifiedFrame);
-}
-
-void nsDisplayItem::SetModifiedFrame(bool aModified) {
-  if (aModified) {
-    mItemFlags += ItemFlag::ModifiedFrame;
-  } else {
-    mItemFlags -= ItemFlag::ModifiedFrame;
-  }
-}
-
-bool nsDisplayItem::HasDeletedFrame() const {
-  return mItemFlags.contains(ItemFlag::DeletedFrame) ||
-         (GetType() == DisplayItemType::TYPE_REMOTE &&
-          !static_cast<const nsDisplayRemote*>(this)->GetFrameLoader());
-}
-
 int32_t nsDisplayItem::ZIndex() const { return mFrame->ZIndex(); }
 
 bool nsDisplayItem::ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                       nsRegion* aVisibleRegion) {
   return !GetPaintRect().IsEmpty() &&
          !IsInvisibleInRect(aVisibleRegion->GetBounds());
 }
 
@@ -3308,18 +3309,16 @@ void nsDisplayItem::FuseClipChainUpTo(ns
 
   if (mClipChain) {
     mClip = &mClipChain->mClip;
   } else {
     mClip = nullptr;
   }
 }
 
-void nsDisplayItem::SetDeletedFrame() { mItemFlags += ItemFlag::DeletedFrame; }
-
 bool nsDisplayItem::ShouldUseAdvancedLayer(LayerManager* aManager,
                                            PrefFunc aFunc) const {
   return CanUseAdvancedLayer(aManager) ? aFunc() : false;
 }
 
 bool nsDisplayItem::CanUseAdvancedLayer(LayerManager* aManager) const {
   return gfxPrefs::LayersAdvancedBasicLayerEnabled() || !aManager ||
          aManager->GetBackendType() == layers::LayersBackend::LAYERS_WR;
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -128,31 +128,16 @@ class Selection;
  * a frame tree containing FRAME/IFRAME elements can include frames from
  * the subdocuments.
  *
  * Display item's coordinates are relative to their nearest reference frame
  * ancestor. Both the display root and any frame with a transform act as a
  * reference frame for their frame subtrees.
  */
 
-// All types are defined in nsDisplayItemTypes.h
-#define NS_DISPLAY_DECL_NAME(n, e)                                        \
-  const char* Name() const override { return n; }                         \
-  DisplayItemType GetType() const override { return DisplayItemType::e; } \
-                                                                          \
- private:                                                                 \
-  void* operator new(size_t aSize, nsDisplayListBuilder* aBuilder) {      \
-    return aBuilder->Allocate(aSize, DisplayItemType::e);                 \
-  }                                                                       \
-  template <typename T, typename... Args>                                 \
-  friend T* ::MakeDisplayItem(nsDisplayListBuilder* aBuilder,             \
-                              Args&&... aArgs);                           \
-                                                                          \
- public:
-
 /**
  * Represents a frame that is considered to have (or will have) "animated
  * geometry" for itself and descendant frames.
  *
  * For example the scrolled frames of scrollframes which are actively being
  * scrolled fall into this category. Frames with certain CSS properties that are
  * being animated (e.g. 'left'/'top' etc) are also placed in this category.
  * Frames with different active geometry roots are in different PaintedLayers,
@@ -2003,45 +1988,50 @@ class nsDisplayListBuilder {
   bool mIsInActiveDocShell;
   bool mBuildAsyncZoomContainer;
 
   nsRect mHitTestArea;
   CompositorHitTestInfo mHitTestInfo;
 };
 
 class nsDisplayItem;
+class nsDisplayItemBase;
+class nsDisplayWrapList;
 class nsDisplayList;
 class RetainedDisplayList;
-/**
- * nsDisplayItems are put in singly-linked lists rooted in an nsDisplayList.
- * nsDisplayItemLink holds the link. The lists are linked from lowest to
- * highest in z-order.
- */
-class nsDisplayItemLink {
-  // This is never instantiated directly, so no need to count constructors and
-  // destructors.
- protected:
-  nsDisplayItemLink() : mAbove(nullptr) {}
-  nsDisplayItemLink(const nsDisplayItemLink&) : mAbove(nullptr) {}
-  nsDisplayItem* mAbove;
-
-  friend class nsDisplayList;
-};
-
-class nsDisplayWrapList;
+
+// 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; } \
+                                                                             \
+ private:                                                                    \
+  void* operator new(size_t aSize, nsDisplayListBuilder* aBuilder) {         \
+    return aBuilder->Allocate(aSize, DisplayItemType::e);                    \
+  }                                                                          \
+                                                                             \
+  template <typename T, typename... Args>                                    \
+  friend T* ::MakeDisplayItem(nsDisplayListBuilder* aBuilder,                \
+                              Args&&... aArgs);                              \
+                                                                             \
+ public:
 
 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
 void AssertUniqueItem(nsDisplayItem* aItem);
 #endif
 
 template <typename T, typename... Args>
 MOZ_ALWAYS_INLINE T* MakeDisplayItem(nsDisplayListBuilder* aBuilder,
                                      Args&&... aArgs) {
   T* item = new (aBuilder) T(aBuilder, std::forward<Args>(aArgs)...);
 
+  if (T::ItemType() != DisplayItemType::TYPE_GENERIC) {
+    item->SetType(T::ItemType());
+  }
+
   // TODO: Ideally we'd determine this before constructing the item,
   // but we'd need a template specialization for every type that has
   // children, or make all callers pass the type.
   if (aBuilder->InEventsAndPluginsOnly() &&
       item->GetType() != DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO &&
       item->GetType() != DisplayItemType::TYPE_PLUGIN && !item->GetChildren()) {
     item->Destroy(aBuilder);
     return nullptr;
@@ -2078,31 +2068,278 @@ MOZ_ALWAYS_INLINE T* MakeDisplayItem(nsD
         AnyContentAncestorModified(item->FrameForInvalidation()));
   }
 #endif
 
   return item;
 }
 
 /**
- * This is the unit of rendering and event testing. Each instance of this
- * class represents an entity that can be drawn on the screen, e.g., a
- * frame's CSS background, or a frame's text string.
+ * nsDisplayItems are put in singly-linked lists rooted in an nsDisplayList.
+ * nsDisplayItemLink holds the link. The lists are linked from lowest to
+ * highest in z-order.
+ */
+class nsDisplayItemLink {
+  // This is never instantiated directly, so no need to count constructors and
+  // destructors.
+ protected:
+  nsDisplayItemLink() : mAbove(nullptr) {}
+  nsDisplayItemLink(const nsDisplayItemLink&) : mAbove(nullptr) {}
+  nsDisplayItem* mAbove;
+
+  friend class nsDisplayList;
+};
+
+/*
+ * nsDisplayItemBase is a base-class for all display items. It is mainly
+ * responsible for handling the frame-display item 1:n relationship, as well as
+ * storing the state needed for display list merging.
  *
- * nsDisplayItems can be containers --- i.e., they can perform hit testing
- * and painting by recursively traversing a list of child items.
+ * Display items are arena-allocated during display list construction.
  *
- * These are arena-allocated during display list construction. A typical
- * subclass would just have a frame pointer, so its object would be just three
- * pointers (vtable, next-item, frame).
+ * Display items can be containers --- i.e., they can perform hit testing
+ * and painting by recursively traversing a list of child items.
  *
  * Display items belong to a list at all times (except temporarily as they
  * move from one list to another).
  */
-class nsDisplayItem : public nsDisplayItemLink {
+class nsDisplayItemBase : public nsDisplayItemLink {
+ public:
+  nsDisplayItemBase() = delete;
+
+  /**
+   * Frees the memory allocated for this display item.
+   * The given display list builder must have allocated this display item.
+   */
+  virtual void Destroy(nsDisplayListBuilder* aBuilder) {
+    const DisplayItemType type = GetType();
+    this->~nsDisplayItemBase();
+    aBuilder->Destroy(type, this);
+  }
+
+  /**
+   * Returns the frame that this display item was created for.
+   * Never returns null.
+   */
+  inline nsIFrame* Frame() const {
+    MOZ_ASSERT(mFrame, "Trying to use display item after deletion!");
+    return mFrame;
+  }
+
+  /**
+   * Called when the display item is prepared for deletion. The display item
+   * should not be used after calling this function.
+   */
+  virtual void RemoveFrame(nsIFrame* aFrame) {
+    MOZ_ASSERT(aFrame);
+
+    if (mFrame && aFrame == mFrame) {
+      MOZ_ASSERT(!mFrame->HasDisplayItem(this));
+      mFrame = nullptr;
+      SetDeletedFrame();
+    }
+  }
+
+  /**
+   * A display item can depend on multiple different frames for invalidation.
+   */
+  virtual nsIFrame* GetDependentFrame() { return nullptr; }
+
+  /**
+   * Returns the frame that provides the style data, and should
+   * be checked when deciding if this display item can be reused.
+   */
+  virtual nsIFrame* FrameForInvalidation() const { return Frame(); }
+
+  /**
+   * Returns the printable name of this display item.
+   */
+  virtual const char* Name() const = 0;
+
+  /**
+   * Some consecutive items should be rendered together as a unit, e.g.,
+   * outlines for the same element. For this, we need a way for items to
+   * identify their type. We use the type for other purposes too.
+   */
+  DisplayItemType GetType() const { return mType; }
+  void SetType(const DisplayItemType aType) { mType = aType; }
+
+  /**
+   * Pairing this with the Frame() pointer gives a key that
+   * uniquely identifies this display item in the display item tree.
+   */
+  virtual uint32_t GetPerFrameKey() const { return uint32_t(GetType()); }
+  void SetPerFrameKey(const uint32_t aKey) { mKey = aKey; }
+
+  /**
+   * Returns true if this item was reused during display list merging.
+   */
+  bool IsReused() const {
+    return mItemFlags.contains(ItemBaseFlag::ReusedItem);
+  }
+
+  void SetReused(bool aReused) {
+    if (aReused) {
+      mItemFlags += ItemBaseFlag::ReusedItem;
+    } else {
+      mItemFlags -= ItemBaseFlag::ReusedItem;
+    }
+  }
+
+  /**
+   * Returns true if this item can be reused during display list merging.
+   */
+  bool CanBeReused() const {
+    return !mItemFlags.contains(ItemBaseFlag::CantBeReused);
+  }
+
+  void SetCantBeReused() { mItemFlags += ItemBaseFlag::CantBeReused; }
+
+  void DiscardIfOldItem() {
+    if (mOldList) {
+      SetCantBeReused();
+    }
+  }
+
+  /**
+   * Returns true if the frame of this display item is in a modified subtree.
+   */
+  bool HasModifiedFrame() const;
+  void SetModifiedFrame(bool aModified);
+  bool HasDeletedFrame() const;
+
+  /**
+   * Set the nsDisplayList that this item belongs to, and what index it is
+   * within that list.
+   * Temporary state for merging used by RetainedDisplayListBuilder.
+   */
+  void SetOldListIndex(nsDisplayList* aList, OldListIndex aIndex,
+                       uint32_t aListKey, uint32_t aNestingDepth) {
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
+    mOldListKey = aListKey;
+    mOldNestingDepth = aNestingDepth;
+#endif
+    mOldList = reinterpret_cast<uintptr_t>(aList);
+    mOldListIndex = aIndex;
+  }
+
+  bool GetOldListIndex(nsDisplayList* aList, uint32_t aListKey,
+                       OldListIndex* aOutIndex) {
+    if (mOldList != reinterpret_cast<uintptr_t>(aList)) {
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
+      MOZ_CRASH_UNSAFE_PRINTF(
+          "Item found was in the wrong list! type %d "
+          "(outer type was %d at depth %d, now is %d)",
+          GetPerFrameKey(), mOldListKey, mOldNestingDepth, aListKey);
+#endif
+      return false;
+    }
+    *aOutIndex = mOldListIndex;
+    return true;
+  }
+
+  /**
+   * Returns the display list containing the children of this display item.
+   * The children may be in a different coordinate system than this item.
+   */
+  virtual RetainedDisplayList* GetChildren() const { return nullptr; }
+  bool HasChildren() const { return GetChildren(); }
+
+  /**
+   * Display items with children may return true here. This causes the
+   * display list iterator to descend into the child display list.
+   */
+  virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) {
+    return false;
+  }
+
+ protected:
+  nsDisplayItemBase(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
+      : mFrame(aFrame) {
+    MOZ_COUNT_CTOR(nsDisplayItemBase);
+    MOZ_ASSERT(mFrame);
+
+    if (aBuilder->IsRetainingDisplayList()) {
+      mFrame->AddDisplayItem(this);
+    }
+  }
+
+  nsDisplayItemBase(nsDisplayListBuilder* aBuilder,
+                    const nsDisplayItemBase& aOther)
+      : mFrame(aOther.mFrame),
+        mItemFlags(aOther.mItemFlags),
+        mType(aOther.mType),
+        mKey(aOther.mKey) {
+    MOZ_COUNT_CTOR(nsDisplayItemBase);
+  }
+
+  virtual ~nsDisplayItemBase() {
+    MOZ_COUNT_DTOR(nsDisplayItemBase);
+    if (mFrame) {
+      mFrame->RemoveDisplayItem(this);
+    }
+  }
+
+  void SetDeletedFrame();
+
+  nsIFrame* mFrame;  // 8
+
+ private:
+  enum class ItemBaseFlag : uint8_t {
+    CantBeReused,
+    DeletedFrame,
+    ModifiedFrame,
+    ReusedItem,
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
+    MergedItem,
+    PreProcessedItem,
+#endif
+  };
+
+  mozilla::EnumSet<ItemBaseFlag, uint8_t> mItemFlags;  // 1
+  DisplayItemType mType;                               // 1
+  uint16_t mKey;                                       // 2
+  OldListIndex mOldListIndex;                          // 4
+  uintptr_t mOldList = 0;                              // 8
+
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
+ public:
+  bool IsMergedItem() const {
+    return mItemFlags.contains(ItemBaseFlag::MergedItem);
+  }
+
+  bool IsPreProcessedItem() const {
+    return mItemFlags.contains(ItemBaseFlag::PreProcessedItem);
+  }
+
+  void SetMergedPreProcessed(bool aMerged, bool aPreProcessed) {
+    if (aMerged) {
+      mItemFlags += ItemBaseFlag::MergedItem;
+    } else {
+      mItemFlags -= ItemBaseFlag::MergedItem;
+    }
+
+    if (aPreProcessed) {
+      mItemFlags += ItemBaseFlag::PreProcessedItem;
+    } else {
+      mItemFlags -= ItemBaseFlag::PreProcessedItem;
+    }
+  }
+
+  uint32_t mOldListKey = 0;
+  uint32_t mOldNestingDepth = 0;
+#endif
+};
+
+/**
+ * This is the unit of rendering and event testing. Each instance of this
+ * class represents an entity that can be drawn on the screen, e.g., a
+ * frame's CSS background, or a frame's text string.
+ */
+class nsDisplayItem : public nsDisplayItemBase {
  public:
   typedef mozilla::ContainerLayerParameters ContainerLayerParameters;
   typedef mozilla::DisplayItemClip DisplayItemClip;
   typedef mozilla::DisplayItemClipChain DisplayItemClipChain;
   typedef mozilla::ActiveScrolledRoot ActiveScrolledRoot;
   typedef mozilla::layers::FrameMetrics FrameMetrics;
   typedef mozilla::layers::ScrollMetadata ScrollMetadata;
   typedef mozilla::layers::ScrollableLayerGuid::ViewID ViewID;
@@ -2112,55 +2349,37 @@ class nsDisplayItem : public nsDisplayIt
   typedef mozilla::layers::WebRenderCommand WebRenderCommand;
   typedef mozilla::layers::WebRenderParentCommand WebRenderParentCommand;
   typedef mozilla::LayerState LayerState;
   typedef mozilla::image::imgDrawingParams imgDrawingParams;
   typedef mozilla::image::ImgDrawResult ImgDrawResult;
   typedef class mozilla::gfx::DrawTarget DrawTarget;
   typedef mozilla::gfx::CompositorHitTestInfo CompositorHitTestInfo;
 
+ 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);
 
-  nsDisplayItem() = delete;
-
- protected:
   virtual ~nsDisplayItem() {
     MOZ_COUNT_DTOR(nsDisplayItem);
     SetDisplayItemData(nullptr, nullptr);
-    if (mFrame) {
-      mFrame->RemoveDisplayItem(this);
-    }
   }
 
  public:
-  virtual void Destroy(nsDisplayListBuilder* aBuilder) {
-    DisplayItemType type = GetType();
-    this->~nsDisplayItem();
-    aBuilder->Destroy(type, this);
-  }
+  nsDisplayItem() = delete;
 
   virtual void RestoreState() {
     mClipChain = mState.mClipChain;
     mClip = mState.mClip;
     mItemFlags -= ItemFlag::DisableSubpixelAA;
   }
 
-  virtual void RemoveFrame(nsIFrame* aFrame) {
-    if (mFrame && aFrame == mFrame) {
-      MOZ_ASSERT(!mFrame->HasDisplayItem(this));
-      mFrame = nullptr;
-      SetDeletedFrame();
-      SetDisplayItemData(nullptr, nullptr);
-    }
-  }
-
   /**
    * Downcasts this item to nsDisplayWrapList, if possible.
    */
   virtual const nsDisplayWrapList* AsDisplayWrapList() const { return nullptr; }
   virtual nsDisplayWrapList* AsDisplayWrapList() { return nullptr; }
 
   /**
    * Create a clone of this item.
@@ -2171,18 +2390,17 @@ class nsDisplayItem : public nsDisplayIt
 
   nsDisplayItem(const nsDisplayItem&) = delete;
   /**
    * 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)
-      : mFrame(aOther.mFrame),
-        mItemFlags(),
+      : nsDisplayItemBase(aBuilder, aOther),
         mClipChain(aOther.mClipChain),
         mClip(aOther.mClip),
         mActiveScrolledRoot(aOther.mActiveScrolledRoot),
         mReferenceFrame(aOther.mReferenceFrame),
         mAnimatedGeometryRoot(aOther.mAnimatedGeometryRoot),
         mToReferenceFrame(aOther.mToReferenceFrame),
         mBuildingRect(aOther.mBuildingRect),
         mPaintRect(aOther.mPaintRect) {
@@ -2210,29 +2428,16 @@ class nsDisplayItem : public nsDisplayIt
                    "mItemBuffer should have been cleared");
     }
 
     // Handling transform items for preserve 3D frames.
     bool mInPreserves3D;
     AutoTArray<nsDisplayItem*, 100> mItemBuffer;
   };
 
-  /**
-   * Some consecutive items should be rendered together as a unit, e.g.,
-   * outlines for the same element. For this, we need a way for items to
-   * identify their type. We use the type for other purposes too.
-   */
-  virtual DisplayItemType GetType() const = 0;
-  /**
-   * Pairing this with the GetUnderlyingFrame() pointer gives a key that
-   * uniquely identifies this display item in the display item tree.
-   * XXX check nsOptionEventGrabberWrapper/nsXULEventRedirectorWrapper
-   */
-  virtual uint32_t GetPerFrameKey() const { return uint32_t(GetType()); }
-
   uint8_t GetFlags() const { return GetDisplayItemFlagsForType(GetType()); }
 
   virtual bool IsContentful() const { return GetFlags() & TYPE_IS_CONTENTFUL; }
 
   /**
    * This is called after we've constructed a display list for event handling.
    * When this is called, we've already ensured that aRect intersects the
    * item's bounds and that clipping has been taking into account.
@@ -2242,36 +2447,16 @@ class nsDisplayItem : public nsDisplayIt
    * hit testing a point, not a rect.
    * @param aState must point to a HitTestState. If you don't have one,
    * just create one with the default constructor and pass it in.
    * @param aOutFrames each item appends the frame(s) in this display item that
    * the rect is considered over (if any) to aOutFrames.
    */
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) {}
-  /**
-   * @return the frame that this display item is based on. This is used to sort
-   * items by z-index and content order and for some other uses. Never
-   * returns null.
-   */
-  inline nsIFrame* Frame() const {
-    MOZ_ASSERT(mFrame, "Trying to use display item after deletion!");
-    return mFrame;
-  }
-
-  /**
-   * @return the nsIFrame that provides the style data, and should
-   * be checked when deciding if this display item can be reused.
-   */
-  virtual nsIFrame* FrameForInvalidation() const { return mFrame; }
-
-  bool HasModifiedFrame() const;
-  void SetModifiedFrame(bool aModified);
-
-  bool HasDeletedFrame() const;
 
   virtual nsIFrame* StyleFrame() const { return mFrame; }
 
   /**
    * Compute the used z-index of our frame; returns zero for elements to which
    * z-index does not apply, and for z-index:auto.
    * @note This can be overridden, @see nsDisplayWrapList::SetOverrideZIndex.
    */
@@ -2626,26 +2811,16 @@ class nsDisplayItem : public nsDisplayIt
    * merged into this one (excluding  this item's own underlying frame)
    * to aFrames.
    */
   virtual void GetMergedFrames(nsTArray<nsIFrame*>* aFrames) const {}
 
   virtual bool HasMergedFrames() const { return false; }
 
   /**
-   * During the visibility computation and after TryMerge, display lists may
-   * return true here to flatten themselves away, removing them. This
-   * flattening is distinctly different from FlattenTo, which occurs before
-   * items are merged together.
-   */
-  virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) {
-    return false;
-  }
-
-  /**
    * Returns true if this item needs to have its geometry updated, despite
    * returning empty invalidation region.
    */
   virtual bool NeedsGeometryUpdates() const { return false; }
 
   /**
    * Some items such as those calling into the native themed widget machinery
    * have to be painted on the content process. In this case it is best to avoid
@@ -2675,22 +2850,16 @@ class nsDisplayItem : public nsDisplayIt
    * The bounds of a transform item with the frame establishing 3D
    * rendering context should be computed by calling
    * DoUpdateBoundsPreserves3D() on all descendants that participate
    * the same 3d rendering context.
    */
   virtual void DoUpdateBoundsPreserves3D(nsDisplayListBuilder* aBuilder) {}
 
   /**
-   * If this has a child list, return it, even if the children are in
-   * a different coordinate system to this item.
-   */
-  virtual RetainedDisplayList* GetChildren() const { return nullptr; }
-
-  /**
    * Returns the building rectangle used by nsDisplayListBuilder when
    * this item was constructed.
    */
   const nsRect& GetBuildingRect() const { return mBuildingRect; }
 
   void SetBuildingRect(const nsRect& aBuildingRect) {
     if (aBuildingRect == mBuildingRect) {
       // Avoid unnecessary paint rect recompution when the
@@ -2732,21 +2901,16 @@ class nsDisplayItem : public nsDisplayIt
    * without actually applying the opacity. Otherwise returns false.
    */
   virtual bool CanApplyOpacity() const { return false; }
 
   bool ForceNotVisible() const {
     return mItemFlags.contains(ItemFlag::ForceNotVisible);
   }
 
-  /**
-   * For debugging and stuff
-   */
-  virtual const char* Name() const = 0;
-
   virtual void WriteDebugInfo(std::stringstream& aStream) {}
 
   nsDisplayItem* GetAbove() { return mAbove; }
 
   /**
    * Like ComputeVisibility, but does the work that nsDisplayList
    * does per-item:
    * -- Intersects GetBounds with aVisibleRegion and puts the result
@@ -2862,38 +3026,18 @@ class nsDisplayItem : public nsDisplayIt
     return GetPerFrameKey() == aOther->GetPerFrameKey() &&
            GetClipChain() == aOther->GetClipChain();
   }
 
   bool HasSameContent(const nsDisplayItem* aOther) const {
     return mFrame->GetContent() == aOther->Frame()->GetContent();
   }
 
-  bool IsReused() const { return mItemFlags.contains(ItemFlag::ReusedItem); }
-  void SetReused(bool aReused) {
-    if (aReused) {
-      mItemFlags += ItemFlag::ReusedItem;
-    } else {
-      mItemFlags -= ItemFlag::ReusedItem;
-    }
-  }
-
-  bool CanBeReused() const {
-    return !mItemFlags.contains(ItemFlag::CantBeReused);
-  }
-  void SetCantBeReused() { mItemFlags += ItemFlag::CantBeReused; }
-  void DiscardIfOldItem() {
-    if (mOldList) {
-      SetCantBeReused();
-    }
-  }
   virtual void NotifyUsed(nsDisplayListBuilder* aBuilder) {}
 
-  virtual nsIFrame* GetDependentFrame() { return nullptr; }
-
   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);
@@ -2909,142 +3053,74 @@ class nsDisplayItem : public nsDisplayIt
     mDisplayItemDataLayerManager = aLayerManager;
   }
 
   mozilla::DisplayItemData* GetDisplayItemData() { return mDisplayItemData; }
   mozilla::layers::LayerManager* GetDisplayItemDataLayerManager() {
     return mDisplayItemDataLayerManager;
   }
 
-  // Set the nsDisplayList that this item belongs to, and what
-  // index it is within that list. Temporary state for merging
-  // used by RetainedDisplayListBuilder.
-  void SetOldListIndex(nsDisplayList* aList, OldListIndex aIndex,
-                       uint32_t aListKey, uint32_t aNestingDepth) {
-#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
-    mOldListKey = aListKey;
-    mOldNestingDepth = aNestingDepth;
-#endif
-    mOldList = reinterpret_cast<uintptr_t>(aList);
-    mOldListIndex = aIndex;
-  }
-  bool GetOldListIndex(nsDisplayList* aList, uint32_t aListKey,
-                       OldListIndex* aOutIndex) {
-    if (mOldList != reinterpret_cast<uintptr_t>(aList)) {
-#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
-      MOZ_CRASH_UNSAFE_PRINTF(
-          "Item found was in the wrong list! type %d "
-          "(outer type was %d at depth %d, now is %d)",
-          GetPerFrameKey(), mOldListKey, mOldNestingDepth, aListKey);
-#endif
-      return false;
-    }
-    *aOutIndex = mOldListIndex;
-    return true;
-  }
-
   const nsRect& GetPaintRect() const { return mPaintRect; }
 
   virtual const nsRect& GetUntransformedPaintRect() const {
     return GetPaintRect();
   }
 
   virtual bool HasHitTestInfo() const { return false; }
 
 #ifdef DEBUG
   virtual bool IsHitTestItem() const { return false; }
 #endif
 
  protected:
-  void SetDeletedFrame();
-
   typedef bool (*PrefFunc)(void);
   bool ShouldUseAdvancedLayer(LayerManager* aManager, PrefFunc aFunc) const;
   bool CanUseAdvancedLayer(LayerManager* aManager) const;
 
-  enum class ItemFlag {
-    ModifiedFrame,
-    DeletedFrame,
-    ForceNotVisible,
-    DisableSubpixelAA,
-    CantBeReused,
-    ReusedItem,
-    BackfaceHidden,
-    Combines3DTransformWithAncestors,
-    PaintRectValid,
-#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
-    MergedItem,
-    PreProcessedItem,
-#endif
-#ifdef MOZ_DUMP_PAINTING
-    // True if this frame has been painted.
-    Painted,
-#endif
-  };
-
-  nsIFrame* mFrame;
-  mozilla::EnumSet<ItemFlag, uint16_t> mItemFlags;
   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;
-  mozilla::DisplayItemData* mDisplayItemData = nullptr;
-  mozilla::layers::LayerManager* mDisplayItemDataLayerManager = nullptr;
 
  private:
   // This is the rectangle that nsDisplayListBuilder was using as the visible
   // rect to decide which items to construct.
   nsRect mBuildingRect;
 
   // nsDisplayList::ComputeVisibility sets this to the visible region
   // of the item by intersecting the visible region with the bounds
   // of the item. Paint implementations can use this to limit their drawing.
   // Guaranteed to be contained in GetBounds().
   nsRect mPaintRect;
 
-  OldListIndex mOldListIndex;
-  uintptr_t mOldList = 0;
-
- protected:
-  struct {
-    RefPtr<const DisplayItemClipChain> mClipChain;
-    const DisplayItemClip* mClip;
-  } mState;
-
-#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
- public:
-  bool IsMergedItem() const {
-    return mItemFlags.contains(ItemFlag::MergedItem);
-  }
-  bool IsPreProcessedItem() const {
-    return mItemFlags.contains(ItemFlag::PreProcessedItem);
-  }
-  void SetMergedPreProcessed(bool aMerged, bool aPreProcessed) {
-    if (aMerged) {
-      mItemFlags += ItemFlag::MergedItem;
-    } else {
-      mItemFlags -= ItemFlag::MergedItem;
-    }
-
-    if (aPreProcessed) {
-      mItemFlags += ItemFlag::PreProcessedItem;
-    } else {
-      mItemFlags -= ItemFlag::PreProcessedItem;
-    }
-  }
-
-  uint32_t mOldListKey = 0;
-  uint32_t mOldNestingDepth = 0;
-
- protected:
+  enum class ItemFlag : uint8_t {
+    BackfaceHidden,
+    Combines3DTransformWithAncestors,
+    DisableSubpixelAA,
+    ForceNotVisible,
+    PaintRectValid,
+#ifdef MOZ_DUMP_PAINTING
+    // True if this frame has been painted.
+    Painted,
 #endif
+  };
+
+  mozilla::EnumSet<ItemFlag, uint8_t> mItemFlags;
 };
 
 /**
  * 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
@@ -3849,48 +3925,51 @@ class nsDisplayGeneric : public nsDispla
                                    const nsRect& aDirtyRect, nsPoint aFramePt);
 
   nsDisplayGeneric(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                    PaintCallback aPaint, const char* aName,
                    DisplayItemType aType)
       : nsDisplayItem(aBuilder, aFrame),
         mPaint(aPaint),
         mOldPaint(nullptr),
-        mName(aName),
-        mType(aType) {
+        mName(aName) {
     MOZ_COUNT_CTOR(nsDisplayGeneric);
+    SetType(aType);
   }
 
   // XXX: should be removed eventually
   nsDisplayGeneric(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                    OldPaintCallback aOldPaint, const char* aName,
                    DisplayItemType aType)
       : nsDisplayItem(aBuilder, aFrame),
         mPaint(nullptr),
         mOldPaint(aOldPaint),
-        mName(aName),
-        mType(aType) {
+        mName(aName) {
     MOZ_COUNT_CTOR(nsDisplayGeneric);
+    SetType(aType);
+  }
+
+  constexpr static DisplayItemType ItemType() {
+    return DisplayItemType::TYPE_GENERIC;
   }
 
 #ifdef NS_BUILD_REFCNT_LOGGING
   ~nsDisplayGeneric() override { MOZ_COUNT_DTOR(nsDisplayGeneric); }
 #endif
 
   void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override {
     MOZ_ASSERT(!!mPaint != !!mOldPaint);
     if (mPaint) {
       mPaint(mFrame, aCtx->GetDrawTarget(), GetPaintRect(), ToReferenceFrame());
     } else {
       mOldPaint(mFrame, aCtx, GetPaintRect(), ToReferenceFrame());
     }
   }
 
   const char* Name() const override { return mName; }
-  DisplayItemType GetType() const override { return mType; }
 
   // This override is needed because GetType() for nsDisplayGeneric subclasses
   // does not match TYPE_GENERIC that was used to allocate the object.
   void Destroy(nsDisplayListBuilder* aBuilder) override {
     this->~nsDisplayGeneric();
     aBuilder->Destroy(DisplayItemType::TYPE_GENERIC, this);
   }
 
@@ -3899,17 +3978,16 @@ class nsDisplayGeneric : public nsDispla
     return aBuilder->Allocate(aSize, DisplayItemType::TYPE_GENERIC);
   }
   template <typename T, typename... Args>
   friend T* MakeDisplayItem(nsDisplayListBuilder* aBuilder, Args&&... aArgs);
 
   PaintCallback mPaint;
   OldPaintCallback mOldPaint;  // XXX: should be removed eventually
   const char* mName;
-  DisplayItemType mType;
 };
 
 #if defined(MOZ_REFLOW_PERF_DSP) && defined(MOZ_REFLOW_PERF)
 /**
  * This class implements painting of reflow counts.  Ideally, we would simply
  * make all the frame names be those returned by nsFrame::GetFrameName
  * (except that tosses in the content tag name!)  and support only one color
  * and eliminate this class altogether in favor of nsDisplayGeneric, but for
@@ -6306,20 +6384,21 @@ class nsDisplayAsyncZoom : public nsDisp
       : nsDisplayOwnLayer(aBuilder, aOther), mViewID(aOther.mViewID) {
     MOZ_COUNT_CTOR(nsDisplayAsyncZoom);
   }
 
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayAsyncZoom();
 #endif
 
+  NS_DISPLAY_DECL_NAME("AsyncZoom", TYPE_ASYNC_ZOOM)
+
   virtual already_AddRefed<Layer> BuildLayer(
       nsDisplayListBuilder* aBuilder, LayerManager* aManager,
       const ContainerLayerParameters& aContainerParameters) override;
-  NS_DISPLAY_DECL_NAME("AsyncZoom", TYPE_ASYNC_ZOOM)
   virtual LayerState GetLayerState(
       nsDisplayListBuilder* aBuilder, LayerManager* aManager,
       const ContainerLayerParameters& aParameters) override {
     return mozilla::LAYER_ACTIVE_FORCE;
   }
 
  protected:
   mozilla::layers::FrameMetrics::ViewID mViewID;
@@ -7039,16 +7118,18 @@ class nsDisplayPerspective : public nsDi
 class nsDisplayText final : public nsDisplayItem {
  public:
   nsDisplayText(nsDisplayListBuilder* aBuilder, nsTextFrame* aFrame,
                 const mozilla::Maybe<bool>& aIsSelected);
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayText() { MOZ_COUNT_DTOR(nsDisplayText); }
 #endif
 
+  NS_DISPLAY_DECL_NAME("Text", TYPE_TEXT)
+
   void RestoreState() final {
     mIsFrameSelected.reset();
     mOpacity = 1.0f;
 
     nsDisplayItem::RestoreState();
   }
 
   nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const final {
@@ -7065,17 +7146,16 @@ class nsDisplayText final : public nsDis
 
   bool CreateWebRenderCommands(
       mozilla::wr::DisplayListBuilder& aBuilder,
       mozilla::wr::IpcResourceUpdateQueue& aResources,
       const StackingContextHelper& aSc,
       mozilla::layers::RenderRootStateManager* aManager,
       nsDisplayListBuilder* aDisplayListBuilder) final;
   void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) final;
-  NS_DISPLAY_DECL_NAME("Text", TYPE_TEXT)
 
   nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) const final {
     if (gfxPlatform::GetPlatform()->RespectsFontStyleSmoothing()) {
       // On OS X, web authors can turn off subpixel text rendering using the
       // CSS property -moz-osx-font-smoothing. If they do that, we don't need
       // to use component alpha layers for the affected text.
       if (mFrame->StyleFont()->mFont.smoothing == NS_FONT_SMOOTHING_GRAYSCALE) {
         return nsRect();
@@ -7187,23 +7267,24 @@ class nsDisplaySVGWrapper : public nsDis
       nsDisplayListBuilder* aDisplayListBuilder) override;
 };
 
 /**
  * A display item for webrender to handle SVG foreign object
  */
 class nsDisplayForeignObject : public nsDisplayWrapList {
  public:
-  NS_DISPLAY_DECL_NAME("ForeignObject", TYPE_FOREIGN_OBJECT)
-
   nsDisplayForeignObject(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                          nsDisplayList* aList);
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayForeignObject();
 #endif
+
+  NS_DISPLAY_DECL_NAME("ForeignObject", TYPE_FOREIGN_OBJECT)
+
   virtual already_AddRefed<Layer> BuildLayer(
       nsDisplayListBuilder* aBuilder, LayerManager* aManager,
       const ContainerLayerParameters& aContainerParameters) override;
   virtual LayerState GetLayerState(
       nsDisplayListBuilder* aBuilder, LayerManager* aManager,
       const ContainerLayerParameters& aParameters) override;
   virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override;