Bug 1551986 - Do not create unnecessary items inside opacity: 0 containers r=mattwoodrow
☠☠ backed out by 2c5b7adbd1b0 ☠ ☠
authorMiko Mynttinen <mikokm@gmail.com>
Thu, 16 May 2019 17:23:45 +0000
changeset 532962 8a9694ac64f199178bea35d73467d23ed7a44feb
parent 532961 f8dfee6dc6e57a2a27978313a0409db058a08255
child 532963 888907b9ffc32bbe63f0966a77c4fc8cfa2e7d52
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
bugs1551986
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 1551986 - Do not create unnecessary items inside opacity: 0 containers r=mattwoodrow Differential Revision: https://phabricator.services.mozilla.com/D31311
layout/painting/nsDisplayItemTypes.h
layout/painting/nsDisplayItemTypesList.h
layout/painting/nsDisplayList.cpp
layout/painting/nsDisplayList.h
--- a/layout/painting/nsDisplayItemTypes.h
+++ b/layout/painting/nsDisplayItemTypes.h
@@ -27,17 +27,18 @@ enum class DisplayItemType : uint8_t {
 
 enum {
   // Number of bits needed to represent all types
   TYPE_BITS = 8
 };
 
 enum DisplayItemFlags {
   TYPE_RENDERS_NO_IMAGES = 1 << 0,
-  TYPE_IS_CONTENTFUL = 1 << 1
+  TYPE_IS_CONTENTFUL = 1 << 1,
+  TYPE_IS_CONTAINER = 1 << 2
 };
 
 inline const char* DisplayItemTypeName(DisplayItemType aType) {
   switch (aType) {
 #define DECLARE_DISPLAY_ITEM_TYPE(name, flags) \
   case DisplayItemType::TYPE_##name:           \
     return #name;
 #include "nsDisplayItemTypesList.h"
--- a/layout/painting/nsDisplayItemTypesList.h
+++ b/layout/painting/nsDisplayItemTypesList.h
@@ -1,101 +1,116 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 // IWYU pragma: private, include "nsDisplayList.h"
-DECLARE_DISPLAY_ITEM_TYPE(ASYNC_ZOOM, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(ALT_FEEDBACK, 0)
+DECLARE_DISPLAY_ITEM_TYPE(ASYNC_ZOOM,
+                          TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTAINER)
 DECLARE_DISPLAY_ITEM_TYPE(BACKGROUND, TYPE_IS_CONTENTFUL)
-DECLARE_DISPLAY_ITEM_TYPE(THEMED_BACKGROUND, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(BACKGROUND_COLOR, TYPE_RENDERS_NO_IMAGES)
-DECLARE_DISPLAY_ITEM_TYPE(BLEND_CONTAINER, TYPE_RENDERS_NO_IMAGES)
-DECLARE_DISPLAY_ITEM_TYPE(TABLE_BLEND_CONTAINER, TYPE_RENDERS_NO_IMAGES)
-DECLARE_DISPLAY_ITEM_TYPE(BLEND_MODE, TYPE_RENDERS_NO_IMAGES)
-DECLARE_DISPLAY_ITEM_TYPE(TABLE_BLEND_MODE, TYPE_RENDERS_NO_IMAGES)
+DECLARE_DISPLAY_ITEM_TYPE(BLEND_CONTAINER,
+                          TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTAINER)
+DECLARE_DISPLAY_ITEM_TYPE(BLEND_MODE,
+                          TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTAINER)
 DECLARE_DISPLAY_ITEM_TYPE(BORDER, 0)
+DECLARE_DISPLAY_ITEM_TYPE(BOX_SHADOW_INNER, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(BOX_SHADOW_OUTER, TYPE_RENDERS_NO_IMAGES)
-DECLARE_DISPLAY_ITEM_TYPE(BOX_SHADOW_INNER, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(BULLET, TYPE_IS_CONTENTFUL)
 DECLARE_DISPLAY_ITEM_TYPE(BUTTON_BORDER_BACKGROUND, TYPE_IS_CONTENTFUL)
 DECLARE_DISPLAY_ITEM_TYPE(BUTTON_BOX_SHADOW_OUTER,
                           TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTENTFUL)
 DECLARE_DISPLAY_ITEM_TYPE(BUTTON_FOREGROUND, TYPE_IS_CONTENTFUL)
 DECLARE_DISPLAY_ITEM_TYPE(CANVAS, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(CANVAS_BACKGROUND_COLOR, TYPE_RENDERS_NO_IMAGES)
+DECLARE_DISPLAY_ITEM_TYPE(CANVAS_BACKGROUND_IMAGE, TYPE_IS_CONTENTFUL)
+DECLARE_DISPLAY_ITEM_TYPE(CANVAS_FOCUS, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(CANVAS_THEMED_BACKGROUND,
                           TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTENTFUL)
-DECLARE_DISPLAY_ITEM_TYPE(CANVAS_BACKGROUND_IMAGE, TYPE_IS_CONTENTFUL)
-DECLARE_DISPLAY_ITEM_TYPE(CANVAS_FOCUS, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(CARET, TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTENTFUL)
 DECLARE_DISPLAY_ITEM_TYPE(CHECKED_CHECKBOX,
                           TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTENTFUL)
 DECLARE_DISPLAY_ITEM_TYPE(CHECKED_RADIOBUTTON,
                           TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTENTFUL)
 DECLARE_DISPLAY_ITEM_TYPE(CLEAR_BACKGROUND, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(COLUMN_RULE, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(COMBOBOX_FOCUS, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(COMPOSITOR_HITTEST_INFO, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(EVENT_RECEIVER, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(FIELDSET_BORDER_BACKGROUND, 0)
-DECLARE_DISPLAY_ITEM_TYPE(FIXED_POSITION, TYPE_RENDERS_NO_IMAGES)
-DECLARE_DISPLAY_ITEM_TYPE(STICKY_POSITION, TYPE_RENDERS_NO_IMAGES)
+DECLARE_DISPLAY_ITEM_TYPE(FILTER, TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTAINER)
+DECLARE_DISPLAY_ITEM_TYPE(FIXED_POSITION,
+                          TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTAINER)
+DECLARE_DISPLAY_ITEM_TYPE(FOREIGN_OBJECT,
+                          TYPE_IS_CONTENTFUL | TYPE_IS_CONTAINER)
+DECLARE_DISPLAY_ITEM_TYPE(FRAMESET_BLANK, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(FRAMESET_BORDER, TYPE_RENDERS_NO_IMAGES)
-DECLARE_DISPLAY_ITEM_TYPE(FRAMESET_BLANK, TYPE_RENDERS_NO_IMAGES)
+DECLARE_DISPLAY_ITEM_TYPE(GENERIC, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(HEADER_FOOTER, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(IMAGE, TYPE_IS_CONTENTFUL)
 DECLARE_DISPLAY_ITEM_TYPE(LIST_FOCUS, TYPE_RENDERS_NO_IMAGES)
-DECLARE_DISPLAY_ITEM_TYPE(OPACITY, TYPE_RENDERS_NO_IMAGES)
-DECLARE_DISPLAY_ITEM_TYPE(OPTION_EVENT_GRABBER, TYPE_RENDERS_NO_IMAGES)
+DECLARE_DISPLAY_ITEM_TYPE(MASK, TYPE_IS_CONTAINER)
+DECLARE_DISPLAY_ITEM_TYPE(OPACITY, TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTAINER)
+DECLARE_DISPLAY_ITEM_TYPE(OPTION_EVENT_GRABBER,
+                          TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTAINER)
 DECLARE_DISPLAY_ITEM_TYPE(OUTLINE, TYPE_RENDERS_NO_IMAGES)
-DECLARE_DISPLAY_ITEM_TYPE(OWN_LAYER, TYPE_RENDERS_NO_IMAGES)
+DECLARE_DISPLAY_ITEM_TYPE(OWN_LAYER, TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTAINER)
+DECLARE_DISPLAY_ITEM_TYPE(PERSPECTIVE,
+                          TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTAINER)
 DECLARE_DISPLAY_ITEM_TYPE(PLUGIN, 0)
 DECLARE_DISPLAY_ITEM_TYPE(PLUGIN_READBACK, 0)
 DECLARE_DISPLAY_ITEM_TYPE(PRINT_PLUGIN, 0)
 DECLARE_DISPLAY_ITEM_TYPE(RANGE_FOCUS_RING, 0)
 DECLARE_DISPLAY_ITEM_TYPE(REMOTE, TYPE_RENDERS_NO_IMAGES)
-DECLARE_DISPLAY_ITEM_TYPE(RENDER_ROOT, TYPE_RENDERS_NO_IMAGES)
-DECLARE_DISPLAY_ITEM_TYPE(RESOLUTION, TYPE_RENDERS_NO_IMAGES)
-DECLARE_DISPLAY_ITEM_TYPE(SCROLL_INFO_LAYER, TYPE_RENDERS_NO_IMAGES)
+DECLARE_DISPLAY_ITEM_TYPE(RENDER_ROOT,
+                          TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTAINER)
+DECLARE_DISPLAY_ITEM_TYPE(RESOLUTION,
+                          TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTAINER)
+DECLARE_DISPLAY_ITEM_TYPE(SCROLL_INFO_LAYER,
+                          TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTAINER)
 DECLARE_DISPLAY_ITEM_TYPE(SELECTION_OVERLAY, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(SOLID_COLOR, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(SOLID_COLOR_REGION, TYPE_RENDERS_NO_IMAGES)
-DECLARE_DISPLAY_ITEM_TYPE(SUBDOCUMENT, TYPE_RENDERS_NO_IMAGES)
-DECLARE_DISPLAY_ITEM_TYPE(MASK, 0)
-DECLARE_DISPLAY_ITEM_TYPE(FILTER, TYPE_RENDERS_NO_IMAGES)
+DECLARE_DISPLAY_ITEM_TYPE(SUBDOCUMENT,
+                          TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTAINER)
+DECLARE_DISPLAY_ITEM_TYPE(STICKY_POSITION,
+                          TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTAINER)
 DECLARE_DISPLAY_ITEM_TYPE(SVG_OUTER_SVG, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(SVG_GEOMETRY, TYPE_IS_CONTENTFUL)
 DECLARE_DISPLAY_ITEM_TYPE(SVG_TEXT, TYPE_IS_CONTENTFUL)
-DECLARE_DISPLAY_ITEM_TYPE(SVG_WRAPPER, 0)
-DECLARE_DISPLAY_ITEM_TYPE(FOREIGN_OBJECT, TYPE_IS_CONTENTFUL)
+DECLARE_DISPLAY_ITEM_TYPE(SVG_WRAPPER, TYPE_IS_CONTAINER)
+DECLARE_DISPLAY_ITEM_TYPE(TABLE_BACKGROUND_COLOR, TYPE_RENDERS_NO_IMAGES)
+DECLARE_DISPLAY_ITEM_TYPE(TABLE_BACKGROUND_IMAGE, TYPE_IS_CONTENTFUL)
+DECLARE_DISPLAY_ITEM_TYPE(TABLE_BLEND_CONTAINER,
+                          TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTAINER)
+DECLARE_DISPLAY_ITEM_TYPE(TABLE_BLEND_MODE, TYPE_RENDERS_NO_IMAGES)
+DECLARE_DISPLAY_ITEM_TYPE(TABLE_BORDER_COLLAPSE, 0)
 DECLARE_DISPLAY_ITEM_TYPE(TABLE_CELL_BACKGROUND, 0)
 DECLARE_DISPLAY_ITEM_TYPE(TABLE_CELL_SELECTION, TYPE_RENDERS_NO_IMAGES)
-DECLARE_DISPLAY_ITEM_TYPE(TABLE_BORDER_COLLAPSE, 0)
-DECLARE_DISPLAY_ITEM_TYPE(TABLE_BACKGROUND_COLOR, TYPE_RENDERS_NO_IMAGES)
-DECLARE_DISPLAY_ITEM_TYPE(TABLE_BACKGROUND_IMAGE, TYPE_IS_CONTENTFUL)
 DECLARE_DISPLAY_ITEM_TYPE(TABLE_THEMED_BACKGROUND_IMAGE, TYPE_IS_CONTENTFUL)
-DECLARE_DISPLAY_ITEM_TYPE(TABLE_FIXED_POSITION, TYPE_RENDERS_NO_IMAGES)
+DECLARE_DISPLAY_ITEM_TYPE(TABLE_FIXED_POSITION,
+                          TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTAINER)
 DECLARE_DISPLAY_ITEM_TYPE(TEXT, TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTENTFUL)
 DECLARE_DISPLAY_ITEM_TYPE(TEXT_OVERFLOW,
                           TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTENTFUL)
-DECLARE_DISPLAY_ITEM_TYPE(TRANSFORM, TYPE_RENDERS_NO_IMAGES)
-DECLARE_DISPLAY_ITEM_TYPE(PERSPECTIVE, TYPE_RENDERS_NO_IMAGES)
+DECLARE_DISPLAY_ITEM_TYPE(THEMED_BACKGROUND, TYPE_RENDERS_NO_IMAGES)
+DECLARE_DISPLAY_ITEM_TYPE(TRANSFORM, TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTAINER)
 DECLARE_DISPLAY_ITEM_TYPE(VIDEO, TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTENTFUL)
-DECLARE_DISPLAY_ITEM_TYPE(WRAP_LIST, TYPE_RENDERS_NO_IMAGES)
-DECLARE_DISPLAY_ITEM_TYPE(ZOOM, TYPE_RENDERS_NO_IMAGES)
-DECLARE_DISPLAY_ITEM_TYPE(GENERIC, TYPE_RENDERS_NO_IMAGES)
+DECLARE_DISPLAY_ITEM_TYPE(WRAP_LIST, TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTAINER)
+DECLARE_DISPLAY_ITEM_TYPE(ZOOM, TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTAINER)
 
 #if defined(MOZ_REFLOW_PERF_DSP) && defined(MOZ_REFLOW_PERF)
 DECLARE_DISPLAY_ITEM_TYPE(REFLOW_COUNT, TYPE_RENDERS_NO_IMAGES)
 #endif
 
 #ifdef MOZ_XUL
-DECLARE_DISPLAY_ITEM_TYPE(XUL_EVENT_REDIRECTOR, TYPE_RENDERS_NO_IMAGES)
+DECLARE_DISPLAY_ITEM_TYPE(XUL_EVENT_REDIRECTOR,
+                          TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTAINER)
 DECLARE_DISPLAY_ITEM_TYPE(XUL_GROUP_BACKGROUND, 0)
 DECLARE_DISPLAY_ITEM_TYPE(XUL_IMAGE, 0)
 DECLARE_DISPLAY_ITEM_TYPE(XUL_TEXT_BOX, TYPE_RENDERS_NO_IMAGES)
 DECLARE_DISPLAY_ITEM_TYPE(XUL_TREE_BODY, 0)
 DECLARE_DISPLAY_ITEM_TYPE(XUL_TREE_COL_SPLITTER_TARGET, TYPE_RENDERS_NO_IMAGES)
 #  ifdef DEBUG_LAYOUT
 DECLARE_DISPLAY_ITEM_TYPE(XUL_DEBUG, TYPE_RENDERS_NO_IMAGES)
 #  endif
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -140,16 +140,22 @@ void AssertUniqueItem(nsDisplayItem* aIt
         continue;
       }
       MOZ_DIAGNOSTIC_ASSERT(false, "Duplicate display item!");
     }
   }
 }
 #endif
 
+bool ShouldBuildItemForEventsOrPlugins(const DisplayItemType aType) {
+  return aType == DisplayItemType::TYPE_COMPOSITOR_HITTEST_INFO ||
+         aType == DisplayItemType::TYPE_PLUGIN ||
+         (GetDisplayItemFlagsForType(aType) & TYPE_IS_CONTAINER);
+}
+
 /* static */
 bool ActiveScrolledRoot::IsAncestor(const ActiveScrolledRoot* aAncestor,
                                     const ActiveScrolledRoot* aDescendant) {
   if (!aAncestor) {
     // nullptr is the root
     return true;
   }
   if (Depth(aAncestor) > Depth(aDescendant)) {
@@ -1249,18 +1255,17 @@ void nsDisplayListBuilder::MarkFrameForD
 
 void nsDisplayListBuilder::AddFrameMarkedForDisplayIfVisible(nsIFrame* aFrame) {
   mFramesMarkedForDisplayIfVisible.AppendElement(aFrame);
 }
 
 void nsDisplayListBuilder::MarkFrameForDisplayIfVisible(
     nsIFrame* aFrame, nsIFrame* aStopAtFrame) {
   AddFrameMarkedForDisplayIfVisible(aFrame);
-  for (nsIFrame* f = aFrame; f;
-       f = nsLayoutUtils::GetDisplayListParent(f)) {
+  for (nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetDisplayListParent(f)) {
     if (f->ForceDescendIntoIfVisible()) return;
     f->SetForceDescendIntoIfVisible(true);
     if (f == aStopAtFrame) {
       // we've reached a frame that we know will be painted, so we can stop.
       break;
     }
   }
 }
@@ -1379,18 +1384,17 @@ static void UnmarkFrameForDisplay(nsIFra
     if (f == aStopAtFrame) {
       // we've reached a frame that we know will be painted, so we can stop.
       break;
     }
   }
 }
 
 static void UnmarkFrameForDisplayIfVisible(nsIFrame* aFrame) {
-  for (nsIFrame* f = aFrame; f;
-       f = nsLayoutUtils::GetDisplayListParent(f)) {
+  for (nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetDisplayListParent(f)) {
     if (!f->ForceDescendIntoIfVisible()) return;
     f->SetForceDescendIntoIfVisible(false);
   }
 }
 
 nsDisplayListBuilder::~nsDisplayListBuilder() {
   NS_ASSERTION(mFramesMarkedForDisplay.Length() == 0,
                "All frames should have been unmarked");
@@ -9948,20 +9952,20 @@ bool nsDisplayFilters::CreateWebRenderCS
           return false;
         }
 
         nsCSSShadowItem* shadow = shadows->ShadowAt(0);
         nscolor color = shadow->mColor.CalcColor(mFrame);
 
         wr::Shadow wrShadow;
         wrShadow.offset = {
-          NSAppUnitsToFloatPixels(shadow->mXOffset, appUnitsPerDevPixel),
-          NSAppUnitsToFloatPixels(shadow->mYOffset, appUnitsPerDevPixel)};
+            NSAppUnitsToFloatPixels(shadow->mXOffset, appUnitsPerDevPixel),
+            NSAppUnitsToFloatPixels(shadow->mYOffset, appUnitsPerDevPixel)};
         wrShadow.blur_radius =
-          NSAppUnitsToFloatPixels(shadow->mRadius, appUnitsPerDevPixel);
+            NSAppUnitsToFloatPixels(shadow->mRadius, appUnitsPerDevPixel);
         wrShadow.color = {NS_GET_R(color) / 255.0f, NS_GET_G(color) / 255.0f,
                           NS_GET_B(color) / 255.0f, NS_GET_A(color) / 255.0f};
         auto filterOp = wr::FilterOp::DropShadow(wrShadow);
 
         wrFilters.filters.AppendElement(filterOp);
         break;
       }
       default:
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -2030,42 +2030,45 @@ MOZ_ALWAYS_INLINE T* MakeClone(nsDisplay
   item->SetPerFrameKey(item->CalculatePerFrameKey());
   return item;
 }
 
 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
 void AssertUniqueItem(nsDisplayItem* aItem);
 #endif
 
+/**
+ * Returns true, if a display item of given |aType| needs to be built within
+ * opacity:0 container.
+ */
+bool ShouldBuildItemForEventsOrPlugins(const DisplayItemType aType);
+
 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");
 
+  const DisplayItemType type = T::ItemType();
+  if (aBuilder->InEventsAndPluginsOnly() &&
+      !ShouldBuildItemForEventsOrPlugins(type)) {
+    // This item is not needed for events or plugins.
+    return nullptr;
+  }
+
   T* item = new (aBuilder) T(aBuilder, aFrame, std::forward<Args>(aArgs)...);
 
-  if (T::ItemType() != DisplayItemType::TYPE_GENERIC) {
-    item->SetType(T::ItemType());
+  if (type != DisplayItemType::TYPE_GENERIC) {
+    item->SetType(type);
   }
 
   item->SetPerFrameKey(item->CalculatePerFrameKey());
 
-  // 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;
-  }
-
   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());
@@ -2086,16 +2089,22 @@ MOZ_ALWAYS_INLINE T* MakeDisplayItem(nsD
     AssertUniqueItem(item);
   }
 
   // Verify that InInvalidSubtree matches invalidation frame's modified state.
   if (aBuilder->InInvalidSubtree()) {
     MOZ_DIAGNOSTIC_ASSERT(
         AnyContentAncestorModified(item->FrameForInvalidation()));
   }
+
+  mozilla::DebugOnly<bool> isContainerType =
+      (GetDisplayItemFlagsForType(type) & TYPE_IS_CONTAINER);
+
+  MOZ_ASSERT(item->HasChildren() == isContainerType,
+             "Container items must have container display item flag set.");
 #endif
 
   return item;
 }
 
 /**
  * nsDisplayItems are put in singly-linked lists rooted in an nsDisplayList.
  * nsDisplayItemLink holds the link. The lists are linked from lowest to