Bug 1551986 - Do not create unnecessary items inside opacity: 0 containers r=mattwoodrow
authorMiko Mynttinen <mikokm@gmail.com>
Thu, 16 May 2019 21:13:49 +0000
changeset 536119 507d95016ed26c189386369dac28bd49c5fb3a7d
parent 536118 3944c733e4179698371ea69f9c462dbc7ed226da
child 536120 7c03af91db0459ce9624dc1a594b9a11b4f18eb4
push id2082
push userffxbld-merge
push dateMon, 01 Jul 2019 08:34:18 +0000
treeherdermozilla-release@2fb19d0466d2 [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,117 @@
 /* -*- 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 | TYPE_IS_CONTAINER)
+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");
@@ -9952,20 +9956,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