Bug 1482403 - Always create nsDisplayOpacity for filters and masks when there is visual opacity r=jwatt
authorMiko Mynttinen <mikokm@gmail.com>
Sun, 14 Oct 2018 19:27:15 +0000
changeset 441170 1feb8b3f06e7f93d1cd67d59011074add931b086
parent 441169 202887e7c361b76d8d3c6f5cb261e71042200ad1
child 441171 f8560f7a88a899e10cc103a25099b3c9fc088247
child 441179 a19f3794f0c9b63868f7e4e028bc6a76fb199930
push id34848
push userrgurzau@mozilla.com
push dateSun, 14 Oct 2018 22:17:37 +0000
treeherdermozilla-central@f8560f7a88a8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwatt
bugs1482403
milestone64.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 1482403 - Always create nsDisplayOpacity for filters and masks when there is visual opacity r=jwatt Differential Revision: https://phabricator.services.mozilla.com/D7183
layout/generic/nsFrame.cpp
layout/painting/RetainedDisplayListBuilder.cpp
layout/painting/nsDisplayList.cpp
layout/painting/nsDisplayList.h
layout/painting/nsDisplayListInvalidation.cpp
layout/painting/nsDisplayListInvalidation.h
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -2670,23 +2670,22 @@ WrapSeparatorTransform(nsDisplayListBuil
   }
 }
 
 // Try to compute a clip rect to bound the contents of the mask item
 // that will be built for |aMaskedFrame|. If we're not able to compute
 // one, return an empty Maybe.
 // The returned clip rect, if there is one, is relative to |aMaskedFrame|.
 static Maybe<nsRect>
-ComputeClipForMaskItem(nsDisplayListBuilder* aBuilder, nsIFrame* aMaskedFrame,
-                       bool aHandleOpacity)
+ComputeClipForMaskItem(nsDisplayListBuilder* aBuilder, nsIFrame* aMaskedFrame)
 {
   const nsStyleSVGReset* svgReset = aMaskedFrame->StyleSVGReset();
 
   nsSVGUtils::MaskUsage maskUsage;
-  nsSVGUtils::DetermineMaskUsage(aMaskedFrame, aHandleOpacity, maskUsage);
+  nsSVGUtils::DetermineMaskUsage(aMaskedFrame, false, maskUsage);
 
   nsPoint offsetToUserSpace = nsLayoutUtils::ComputeOffsetToUserSpace(aBuilder, aMaskedFrame);
   int32_t devPixelRatio = aMaskedFrame->PresContext()->AppUnitsPerDevPixel();
   gfxPoint devPixelOffsetToUserSpace = nsLayoutUtils::PointToGfxPoint(
       offsetToUserSpace, devPixelRatio);
   gfxMatrix cssToDevMatrix = nsSVGUtils::GetCSSPxToDevPxMatrix(aMaskedFrame);
 
   nsPoint toReferenceFrame;
@@ -2930,26 +2929,28 @@ nsIFrame::BuildDisplayListForStackingCon
   if (usingSVGEffects) {
     dirtyRect =
       nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(this, dirtyRect);
     visibleRect =
       nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(this, visibleRect);
     aBuilder->EnterSVGEffectsContents(&hoistedScrollInfoItemsStorage);
   }
 
-
-  bool needsActiveOpacityLayer = false;
-  // We build an opacity item if it's not going to be drawn by SVG content, or
-  // SVG effects. SVG effects won't handle the opacity if we want an active
-  // layer (for async animations), see
-  // nsSVGIntegrationsUtils::PaintMaskAndClipPath or
-  // nsSVGIntegrationsUtils::PaintFilter.
-  bool useOpacity = HasVisualOpacity(effectSet) &&
-                    !nsSVGUtils::CanOptimizeOpacity(this) &&
-                    ((needsActiveOpacityLayer = nsDisplayOpacity::NeedsActiveLayer(aBuilder, this)) || !usingSVGEffects);
+  // We build an opacity item if it's not going to be drawn by SVG content.
+  // We could in principle skip creating an nsDisplayOpacity item if
+  // nsDisplayOpacity::NeedsActiveLayer returns false and usingSVGEffects is
+  // true (the nsDisplayFilter/nsDisplayMasksAndClipPaths could handle the
+  // opacity). Since SVG has perf issues where we sometimes spend a lot of
+  // time creating display list items that might be helpful.  We'd need to
+  // restore our mechanism to do that (changed in bug 1482403), and we'd
+  // need to invalidate the frame if the value that would be return from
+  // NeedsActiveLayer was to change, which we don't currently do.
+  bool useOpacity =
+    HasVisualOpacity(effectSet) && !nsSVGUtils::CanOptimizeOpacity(this);
+
   bool useBlendMode = effects->mMixBlendMode != NS_STYLE_BLEND_NORMAL;
   bool useStickyPosition = disp->mPosition == NS_STYLE_POSITION_STICKY &&
     IsScrollFrameActive(aBuilder,
                         nsLayoutUtils::GetNearestScrollableFrame(GetParent(),
                         nsLayoutUtils::SCROLLABLE_SAME_DOC |
                         nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN));
   bool useFixedPosition = disp->mPosition == NS_STYLE_POSITION_FIXED &&
     (nsLayoutUtils::IsFixedPosFrameInDisplayPort(this) || BuilderHasScrolledClip(aBuilder));
@@ -3011,17 +3012,17 @@ nsIFrame::BuildDisplayListForStackingCon
   }
 
   if (clipCapturedBy != ContainerItemType::eNone) {
     clipState.Clear();
   }
 
   Maybe<nsRect> clipForMask;
   if (usingMask) {
-    clipForMask = ComputeClipForMaskItem(aBuilder, this, !useOpacity);
+    clipForMask = ComputeClipForMaskItem(aBuilder, this);
   }
 
   nsDisplayListCollection set(aBuilder);
   {
     DisplayListClipState::AutoSaveRestore nestedClipState(aBuilder);
     nsDisplayListBuilder::AutoInTransformSetter
       inTransformSetter(aBuilder, inTransform);
     nsDisplayListBuilder::AutoEnterFilter
@@ -3190,25 +3191,19 @@ nsIFrame::BuildDisplayListForStackingCon
     if (clipCapturedBy == ContainerItemType::eFilter) {
       clipState.Restore();
     }
     // Revert to the post-filter dirty rect.
     aBuilder->SetVisibleRect(visibleRectOutsideSVGEffects);
 
     // Skip all filter effects while generating glyph mask.
     if (usingFilter && !aBuilder->IsForGenerateGlyphMask()) {
-      // If we are going to create a mask display item, handle opacity effect
-      // in that mask display item; Otherwise, take care of opacity in this
-      // filter display item.
-      bool handleOpacity = !usingMask && !useOpacity;
-
       /* List now emptied, so add the new list to the top. */
-      resultList.AppendToTop(
-        MakeDisplayItem<nsDisplayFilters>(aBuilder, this, &resultList,
-                                          handleOpacity));
+      resultList.AppendToTop(MakeDisplayItem<nsDisplayFilters>(
+        aBuilder, this, &resultList));
     }
 
     if (usingMask) {
       DisplayListClipState::AutoSaveRestore maskClipState(aBuilder);
       // The mask should move with aBuilder->CurrentActiveScrolledRoot(), so
       // that's the ASR we prefer to use for the mask item. However, we can
       // only do this if the mask if clipped with respect to that ASR, because
       // an item always needs to have finite bounds with respect to its ASR.
@@ -3216,19 +3211,18 @@ nsIFrame::BuildDisplayListForStackingCon
       // using containerItemASR, which is the lowest common ancestor clip of
       // the mask's contents. That's not entirely crrect, but it satisfies
       // the base requirement of the ASR system (that items have finite bounds
       // wrt. their ASR).
       const ActiveScrolledRoot* maskASR = clipForMask.isSome()
                                         ? aBuilder->CurrentActiveScrolledRoot()
                                         : containerItemASR;
       /* List now emptied, so add the new list to the top. */
-      resultList.AppendToTop(
-        MakeDisplayItem<nsDisplayMasksAndClipPaths>(aBuilder, this, &resultList,
-                                                    !useOpacity, maskASR));
+      resultList.AppendToTop(MakeDisplayItem<nsDisplayMasksAndClipPaths>(
+        aBuilder, this, &resultList, maskASR));
     }
 
     // Also add the hoisted scroll info items. We need those for APZ scrolling
     // because nsDisplayMasksAndClipPaths items can't build active layers.
     aBuilder->ExitSVGEffectsContents();
     resultList.AppendToTop(&hoistedScrollInfoItemsStorage);
     if (aCreatedContainerItem) {
       *aCreatedContainerItem = false;
@@ -3238,16 +3232,19 @@ nsIFrame::BuildDisplayListForStackingCon
   /* If the list is non-empty and there is CSS group opacity without SVG
    * effects, wrap it up in an opacity item.
    */
   if (useOpacity) {
     // Don't clip nsDisplayOpacity items. We clip their descendants instead.
     // The clip we would set on an element with opacity would clip
     // all descendant content, but some should not be clipped.
     DisplayListClipState::AutoSaveRestore opacityClipState(aBuilder);
+    const bool needsActiveOpacityLayer =
+      nsDisplayOpacity::NeedsActiveLayer(aBuilder, this);
+
     resultList.AppendToTop(
       MakeDisplayItem<nsDisplayOpacity>(aBuilder, this, &resultList,
                                         containerItemASR,
                                         opacityItemForEventsAndPluginsOnly,
                                         needsActiveOpacityLayer));
     if (aCreatedContainerItem) {
       *aCreatedContainerItem = true;
     }
--- a/layout/painting/RetainedDisplayListBuilder.cpp
+++ b/layout/painting/RetainedDisplayListBuilder.cpp
@@ -409,16 +409,23 @@ public:
 
     if (type == DisplayItemType::TYPE_CARET) {
       // The caret can change position while still being owned by the same frame
       // and we don't invalidate in that case. Use the new version since the
       // changed bounds are needed for DLBI.
       return true;
     }
 
+    if (type == DisplayItemType::TYPE_MASK ||
+        type == DisplayItemType::TYPE_FILTER ||
+        type == DisplayItemType::TYPE_SVG_WRAPPER) {
+      // SVG items have some invalidation issues, see bugs 1494110 and 1494663.
+      return true;
+    }
+
     return false;
   }
 
   RetainedDisplayList Finalize()
   {
     for (size_t i = 0; i < mOldDAG.Length(); i++) {
       if (mOldItems[i].IsUsed()) {
         continue;
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -6534,16 +6534,40 @@ nsDisplayOpacity::ApplyOpacityToChildren
   for (uint32_t i = 0; i < childCount; i++) {
     children[i].item->ApplyOpacity(aBuilder, mOpacity, mClipChain);
   }
 
   mChildOpacityState = ChildOpacityState::Applied;
   return true;
 }
 
+/**
+ * Returns true if this nsDisplayOpacity contains only a filter or a mask item
+ * that has the same frame as the opacity item. In this case the opacity item
+ * can be optimized away.
+ */
+bool
+nsDisplayOpacity::IsEffectsWrapper() const
+{
+  if (mList.Count() != 1) {
+    return false;
+  }
+
+  const nsDisplayItem* item = mList.GetBottom();
+
+  if (item->Frame() != mFrame) {
+    // The effect item needs to have the same frame as the opacity item.
+    return false;
+  }
+
+  const DisplayItemType type = item->GetType();
+  return type == DisplayItemType::TYPE_MASK ||
+         type == DisplayItemType::TYPE_FILTER;
+}
+
 bool
 nsDisplayOpacity::ShouldFlattenAway(nsDisplayListBuilder* aBuilder)
 {
   if (mFrame->GetPrevContinuation() || mFrame->GetNextContinuation() ||
       mFrame->HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT)) {
     // If we've been split, then we might need to merge, so
     // don't flatten us away.
     return false;
@@ -6556,16 +6580,23 @@ nsDisplayOpacity::ShouldFlattenAway(nsDi
     // might trigger repainting).
     return false;
   }
 
   if (mList.IsEmpty()) {
     return false;
   }
 
+  if (IsEffectsWrapper()) {
+    MOZ_ASSERT(nsSVGIntegrationUtils::UsingEffectsForFrame(mFrame));
+    static_cast<nsDisplayEffectsBase*>(mList.GetBottom())->SetHandleOpacity();
+    mChildOpacityState = ChildOpacityState::Applied;
+    return true;
+  }
+
   // Return true if we successfully applied opacity to child items, or if
   // WebRender is not in use. In the latter case, the opacity gets flattened and
   // applied during layer building.
   return ApplyOpacityToChildren(aBuilder) || !gfxVars::UseWebRender();
 }
 
 nsDisplayItem::LayerState
 nsDisplayOpacity::GetLayerState(nsDisplayListBuilder* aBuilder,
@@ -9440,35 +9471,33 @@ nsCharClipDisplayItem::ComputeInvalidati
     aInvalidRegion->Or(oldRect, newRect);
   }
 }
 
 nsDisplayEffectsBase::nsDisplayEffectsBase(
   nsDisplayListBuilder* aBuilder,
   nsIFrame* aFrame,
   nsDisplayList* aList,
-  bool aHandleOpacity,
   const ActiveScrolledRoot* aActiveScrolledRoot,
   bool aClearClipChain)
   : nsDisplayWrapList(aBuilder,
                       aFrame,
                       aList,
                       aActiveScrolledRoot,
                       aClearClipChain)
-  , mHandleOpacity(aHandleOpacity)
+  , mHandleOpacity(false)
 {
   MOZ_COUNT_CTOR(nsDisplayEffectsBase);
 }
 
 nsDisplayEffectsBase::nsDisplayEffectsBase(nsDisplayListBuilder* aBuilder,
                                            nsIFrame* aFrame,
-                                           nsDisplayList* aList,
-                                           bool aHandleOpacity)
+                                           nsDisplayList* aList)
   : nsDisplayWrapList(aBuilder, aFrame, aList)
-  , mHandleOpacity(aHandleOpacity)
+  , mHandleOpacity(false)
 {
   MOZ_COUNT_CTOR(nsDisplayEffectsBase);
 }
 
 nsRegion
 nsDisplayEffectsBase::GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
                                       bool* aSnap) const
 {
@@ -9507,17 +9536,19 @@ nsDisplayEffectsBase::ComputeInvalidatio
   const nsDisplayItemGeometry* aGeometry,
   nsRegion* aInvalidRegion) const
 {
   auto* geometry = static_cast<const nsDisplaySVGEffectGeometry*>(aGeometry);
   bool snap;
   nsRect bounds = GetBounds(aBuilder, &snap);
   if (geometry->mFrameOffsetToReferenceFrame != ToReferenceFrame() ||
       geometry->mUserSpaceOffset != UserSpaceOffset() ||
-      !geometry->mBBox.IsEqualInterior(BBoxInUserSpace())) {
+      !geometry->mBBox.IsEqualInterior(BBoxInUserSpace()) ||
+      geometry->mOpacity != mFrame->StyleEffects()->mOpacity ||
+      geometry->mHandleOpacity != ShouldHandleOpacity()) {
     // Filter and mask output can depend on the location of the frame's user
     // space and on the frame's BBox. We need to invalidate if either of these
     // change relative to the reference frame.
     // Invalidations from our inactive layer manager are not enough to catch
     // some of these cases because filters can produce output even if there's
     // nothing in the filter input.
     aInvalidRegion->Or(bounds, geometry->mBounds);
   }
@@ -9628,22 +9659,20 @@ ComputeMaskGeometry(PaintFramesParams& a
   IntRect result = ComputeClipExtsInDeviceSpace(ctx);
   aParams.maskRect = result;
 }
 
 nsDisplayMasksAndClipPaths::nsDisplayMasksAndClipPaths(
                               nsDisplayListBuilder* aBuilder,
                               nsIFrame* aFrame,
                               nsDisplayList* aList,
-                              bool aHandleOpacity,
                               const ActiveScrolledRoot* aActiveScrolledRoot)
   : nsDisplayEffectsBase(aBuilder,
                          aFrame,
                          aList,
-                         aHandleOpacity,
                          aActiveScrolledRoot,
                          true)
 {
   MOZ_COUNT_CTOR(nsDisplayMasksAndClipPaths);
 
   nsPresContext* presContext = mFrame->PresContext();
   uint32_t flags =
     aBuilder->GetBackgroundPaintFlags() | nsCSSRendering::PAINTBG_MASK_IMAGE;
@@ -9831,21 +9860,16 @@ nsDisplayMasksAndClipPaths::ComputeInval
   nsDisplayEffectsBase::ComputeInvalidationRegion(
     aBuilder, aGeometry, aInvalidRegion);
 
   auto* geometry =
     static_cast<const nsDisplayMasksAndClipPathsGeometry*>(aGeometry);
   bool snap;
   nsRect bounds = GetBounds(aBuilder, &snap);
 
-  if (mFrame->StyleEffects()->mOpacity != geometry->mOpacity ||
-      mHandleOpacity != geometry->mHandleOpacity) {
-    aInvalidRegion->Or(*aInvalidRegion, bounds);
-  }
-
   if (mDestRects.Length() != geometry->mDestRects.Length()) {
     aInvalidRegion->Or(bounds, geometry->mBounds);
   } else {
     for (size_t i = 0; i < mDestRects.Length(); i++) {
       if (!mDestRects[i].IsEqualInterior(geometry->mDestRects[i])) {
         aInvalidRegion->Or(bounds, geometry->mBounds);
         break;
       }
@@ -10027,17 +10051,17 @@ nsDisplayMasksAndClipPaths::GetClipWithR
 #ifdef MOZ_DUMP_PAINTING
 void
 nsDisplayMasksAndClipPaths::PrintEffects(nsACString& aTo)
 {
   nsIFrame* firstFrame =
     nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame);
   bool first = true;
   aTo += " effects=(";
-  if (mFrame->StyleEffects()->mOpacity != 1.0f && mHandleOpacity) {
+  if (mHandleOpacity) {
     first = false;
     aTo += nsPrintfCString("opacity(%f)", mFrame->StyleEffects()->mOpacity);
   }
   nsSVGClipPathFrame* clipPathFrame;
   // XXX Check return value?
   SVGObserverUtils::GetAndObserveClipPath(firstFrame, &clipPathFrame);
   if (clipPathFrame) {
     if (!first) {
@@ -10064,19 +10088,18 @@ nsDisplayMasksAndClipPaths::PrintEffects
     aTo += "mask";
   }
   aTo += ")";
 }
 #endif
 
 nsDisplayFilters::nsDisplayFilters(nsDisplayListBuilder* aBuilder,
                                    nsIFrame* aFrame,
-                                   nsDisplayList* aList,
-                                   bool aHandleOpacity)
-  : nsDisplayEffectsBase(aBuilder, aFrame, aList, aHandleOpacity)
+                                   nsDisplayList* aList)
+  : nsDisplayEffectsBase(aBuilder, aFrame, aList)
   , mEffectsBounds(aFrame->GetVisualOverflowRectRelativeToSelf())
 {
   MOZ_COUNT_CTOR(nsDisplayFilters);
 }
 
 already_AddRefed<Layer>
 nsDisplayFilters::BuildLayer(
   nsDisplayListBuilder* aBuilder,
@@ -10315,17 +10338,17 @@ nsDisplayFilters::CreateWebRenderCommand
 #ifdef MOZ_DUMP_PAINTING
 void
 nsDisplayFilters::PrintEffects(nsACString& aTo)
 {
   nsIFrame* firstFrame =
     nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame);
   bool first = true;
   aTo += " effects=(";
-  if (mFrame->StyleEffects()->mOpacity != 1.0f && mHandleOpacity) {
+  if (mHandleOpacity) {
     first = false;
     aTo += nsPrintfCString("opacity(%f)", mFrame->StyleEffects()->mOpacity);
   }
   // We may exist for a mix of CSS filter functions and/or references to SVG
   // filters.  If we have invalid references to SVG filters then we paint
   // nothing, but otherwise we will apply one or more filters.
   if (SVGObserverUtils::GetAndObserveFilters(firstFrame, nullptr) !=
         SVGObserverUtils::eHasRefsSomeInvalid) {
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -5785,16 +5785,17 @@ public:
     const StackingContextHelper& aSc,
     mozilla::layers::WebRenderLayerManager* aManager,
     nsDisplayListBuilder* aDisplayListBuilder) override;
 
   float GetOpacity() const { return mOpacity; }
 
 private:
   bool ApplyOpacityToChildren(nsDisplayListBuilder* aBuilder);
+  bool IsEffectsWrapper() const;
 
   float mOpacity;
   bool mForEventsAndPluginsOnly : 1;
   enum class ChildOpacityState : uint8_t
   {
     // Our child list has changed since the last time ApplyOpacityToChildren was
     // called.
     Unknown,
@@ -6683,23 +6684,21 @@ private:
  * A base class for different effects types.
  */
 class nsDisplayEffectsBase : public nsDisplayWrapList
 {
 public:
   nsDisplayEffectsBase(nsDisplayListBuilder* aBuilder,
                        nsIFrame* aFrame,
                        nsDisplayList* aList,
-                       bool aHandleOpacity,
                        const ActiveScrolledRoot* aActiveScrolledRoot,
                        bool aClearClipChain = false);
   nsDisplayEffectsBase(nsDisplayListBuilder* aBuilder,
                        nsIFrame* aFrame,
-                       nsDisplayList* aList,
-                       bool aHandleOpacity);
+                       nsDisplayList* aList);
 
   nsDisplayEffectsBase(nsDisplayListBuilder* aBuilder,
                        const nsDisplayEffectsBase& aOther)
     : nsDisplayWrapList(aBuilder, aOther)
     , mEffectsBounds(aOther.mEffectsBounds)
     , mHandleOpacity(aOther.mHandleOpacity)
   {
     MOZ_COUNT_CTOR(nsDisplayEffectsBase);
@@ -6711,22 +6710,25 @@ public:
 
   nsRegion GetOpaqueRegion(nsDisplayListBuilder* aBuilder,
                            bool* aSnap) const override;
   void HitTest(nsDisplayListBuilder* aBuilder,
                const nsRect& aRect,
                HitTestState* aState,
                nsTArray<nsIFrame*>* aOutFrames) override;
 
+  void RestoreState() override { mHandleOpacity = false; }
+
   bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override
   {
     return false;
   }
 
-  bool ShouldHandleOpacity() { return mHandleOpacity; }
+  void SetHandleOpacity() { mHandleOpacity = true; }
+  bool ShouldHandleOpacity() const { return mHandleOpacity; }
 
   gfxRect BBoxInUserSpace() const;
   gfxPoint UserSpaceOffset() const;
 
   void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                  const nsDisplayItemGeometry* aGeometry,
                                  nsRegion* aInvalidRegion) const override;
 
@@ -6752,17 +6754,16 @@ protected:
 class nsDisplayMasksAndClipPaths : public nsDisplayEffectsBase
 {
 public:
   typedef mozilla::layers::ImageLayer ImageLayer;
 
   nsDisplayMasksAndClipPaths(nsDisplayListBuilder* aBuilder,
                              nsIFrame* aFrame,
                              nsDisplayList* aList,
-                             bool aHandleOpacity,
                              const ActiveScrolledRoot* aActiveScrolledRoot);
   nsDisplayMasksAndClipPaths(nsDisplayListBuilder* aBuilder,
                              const nsDisplayMasksAndClipPaths& aOther)
     : nsDisplayEffectsBase(aBuilder, aOther)
     , mDestRects(aOther.mDestRects)
   {
   }
 
@@ -6864,18 +6865,17 @@ private:
  * Note that the filters may just be simple CSS filter functions.  That is,
  * they won't necessarily be references to SVG 'filter' elements.
  */
 class nsDisplayFilters : public nsDisplayEffectsBase
 {
 public:
   nsDisplayFilters(nsDisplayListBuilder* aBuilder,
                    nsIFrame* aFrame,
-                   nsDisplayList* aList,
-                   bool aHandleOpacity);
+                   nsDisplayList* aList);
 
   nsDisplayFilters(nsDisplayListBuilder* aBuilder,
                    const nsDisplayFilters& aOther)
     : nsDisplayEffectsBase(aBuilder, aOther)
     , mEffectsBounds(aOther.mEffectsBounds)
   {
   }
 
--- a/layout/painting/nsDisplayListInvalidation.cpp
+++ b/layout/painting/nsDisplayListInvalidation.cpp
@@ -126,34 +126,34 @@ nsDisplaySolidColorRegionGeometry::MoveB
 
 nsDisplaySVGEffectGeometry::nsDisplaySVGEffectGeometry(
   nsDisplayEffectsBase* aItem,
   nsDisplayListBuilder* aBuilder)
   : nsDisplayItemGeometry(aItem, aBuilder)
   , mBBox(aItem->BBoxInUserSpace())
   , mUserSpaceOffset(aItem->UserSpaceOffset())
   , mFrameOffsetToReferenceFrame(aItem->ToReferenceFrame())
+  , mOpacity(aItem->Frame()->StyleEffects()->mOpacity)
+  , mHandleOpacity(aItem->ShouldHandleOpacity())
 {
 }
 
 void
 nsDisplaySVGEffectGeometry::MoveBy(const nsPoint& aOffset)
 {
   mBounds.MoveBy(aOffset);
   mFrameOffsetToReferenceFrame += aOffset;
 }
 
 nsDisplayMasksAndClipPathsGeometry::nsDisplayMasksAndClipPathsGeometry(
                                       nsDisplayMasksAndClipPaths* aItem,
                                       nsDisplayListBuilder* aBuilder)
   : nsDisplaySVGEffectGeometry(aItem, aBuilder)
   , nsImageGeometryMixin(aItem, aBuilder)
   , mDestRects(aItem->GetDestRects())
-  , mOpacity(aItem->Frame()->StyleEffects()->mOpacity)
-  , mHandleOpacity(aItem->ShouldHandleOpacity())
 {
 }
 
 nsDisplayFiltersGeometry::nsDisplayFiltersGeometry(nsDisplayFilters* aItem,
                                                    nsDisplayListBuilder* aBuilder)
   : nsDisplaySVGEffectGeometry(aItem, aBuilder)
   , nsImageGeometryMixin(aItem, aBuilder)
 {
--- a/layout/painting/nsDisplayListInvalidation.h
+++ b/layout/painting/nsDisplayListInvalidation.h
@@ -297,34 +297,34 @@ public:
   nsDisplaySVGEffectGeometry(nsDisplayEffectsBase* aItem,
                              nsDisplayListBuilder* aBuilder);
 
   void MoveBy(const nsPoint& aOffset) override;
 
   gfxRect mBBox;
   gfxPoint mUserSpaceOffset;
   nsPoint mFrameOffsetToReferenceFrame;
+  float mOpacity;
+  bool mHandleOpacity;
 };
 
 class nsDisplayMasksAndClipPathsGeometry
   : public nsDisplaySVGEffectGeometry
   , public nsImageGeometryMixin<nsDisplayMasksAndClipPathsGeometry>
 {
 public:
   nsDisplayMasksAndClipPathsGeometry(nsDisplayMasksAndClipPaths* aItem,
                                      nsDisplayListBuilder* aBuilder);
 
   bool InvalidateForSyncDecodeImages() const override
   {
     return ShouldInvalidateToSyncDecodeImages();
   }
 
   nsTArray<nsRect> mDestRects;
-  float mOpacity;
-  bool mHandleOpacity;
 };
 
 class nsDisplayFiltersGeometry
   : public nsDisplaySVGEffectGeometry
   , public nsImageGeometryMixin<nsDisplayFiltersGeometry>
 {
 public:
   nsDisplayFiltersGeometry(nsDisplayFilters* aItem,