Bug 1522017 - Introduce StackingContextParams to avoid death by a thousand argument. r=emilio
authorBobby Holley <bobbyholley@gmail.com>
Tue, 22 Jan 2019 17:08:34 -0800
changeset 515321 145d739c4139f2767cb7e1475e17ab7d600dead4
parent 515320 6b7bc40023111979a4755dfeca82629c9c022cd5
child 515322 7ba7f98526f43fff32e7dfced3917400b1eb14eb
push id1953
push userffxbld-merge
push dateMon, 11 Mar 2019 12:10:20 +0000
treeherdermozilla-release@9c35dcbaa899 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersemilio
bugs1522017
milestone66.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 1522017 - Introduce StackingContextParams to avoid death by a thousand argument. r=emilio Differential Revision: https://phabricator.services.mozilla.com/D17434
gfx/layers/wr/AsyncImagePipelineManager.cpp
gfx/layers/wr/StackingContextHelper.cpp
gfx/layers/wr/StackingContextHelper.h
gfx/layers/wr/WebRenderCommandBuilder.cpp
gfx/layers/wr/WebRenderCommandBuilder.h
gfx/layers/wr/WebRenderLayerManager.cpp
gfx/layers/wr/WebRenderLayerManager.h
gfx/webrender_bindings/WebRenderAPI.cpp
gfx/webrender_bindings/WebRenderAPI.h
gfx/webrender_bindings/src/bindings.rs
layout/base/PresShell.cpp
layout/painting/nsDisplayList.cpp
--- a/gfx/layers/wr/AsyncImagePipelineManager.cpp
+++ b/gfx/layers/wr/AsyncImagePipelineManager.cpp
@@ -394,22 +394,24 @@ void AsyncImagePipelineManager::ApplyAsy
 
   aPipeline->mIsChanged = false;
 
   wr::LayoutSize contentSize{aPipeline->mScBounds.Width(),
                              aPipeline->mScBounds.Height()};
   wr::DisplayListBuilder builder(aPipelineId, contentSize);
 
   float opacity = 1.0f;
+  wr::StackingContextParams params;
+  params.opacity = &opacity;
+  params.mTransformPtr =
+      aPipeline->mScTransform.IsIdentity() ? nullptr : &aPipeline->mScTransform;
+  params.mix_blend_mode = aPipeline->mMixBlendMode;
+
   Maybe<wr::WrSpatialId> referenceFrameId = builder.PushStackingContext(
-      wr::ToRoundedLayoutRect(aPipeline->mScBounds),
-      wr::WrStackingContextClip::None(), nullptr, &opacity,
-      aPipeline->mScTransform.IsIdentity() ? nullptr : &aPipeline->mScTransform,
-      wr::TransformStyle::Flat, wr::ReferenceFrameKind::Transform,
-      aPipeline->mMixBlendMode, nsTArray<wr::FilterOp>(), true,
+      params, wr::ToRoundedLayoutRect(aPipeline->mScBounds),
       // This is fine to do unconditionally because we only push images here.
       wr::RasterSpace::Screen());
 
   Maybe<wr::SpaceAndClipChainHelper> spaceAndClipChainHelper;
   if (referenceFrameId) {
     spaceAndClipChainHelper.emplace(builder, referenceFrameId.ref());
   }
 
--- a/gfx/layers/wr/StackingContextHelper.cpp
+++ b/gfx/layers/wr/StackingContextHelper.cpp
@@ -19,45 +19,39 @@ StackingContextHelper::StackingContextHe
       mIsPreserve3D(false),
       mRasterizeLocally(false) {
   // mOrigin remains at 0,0
 }
 
 StackingContextHelper::StackingContextHelper(
     const StackingContextHelper& aParentSC, const ActiveScrolledRoot* aAsr,
     nsIFrame* aContainerFrame, nsDisplayItem* aContainerItem,
-    wr::DisplayListBuilder& aBuilder, const nsTArray<wr::FilterOp>& aFilters,
-    const LayoutDeviceRect& aBounds, const gfx::Matrix4x4* aBoundTransform,
-    const wr::WrAnimationProperty* aAnimation, const float* aOpacityPtr,
-    const gfx::Matrix4x4* aTransformPtr,
-    wr::ReferenceFrameKind aReferenceFrameKind,
-    const gfx::CompositionOp& aMixBlendMode, bool aBackfaceVisible,
-    bool aIsPreserve3D,
-    const Maybe<nsDisplayTransform*>& aDeferredTransformItem,
-    const wr::WrStackingContextClip& aClip, bool aAnimated)
+    wr::DisplayListBuilder& aBuilder, const wr::StackingContextParams& aParams,
+    const LayoutDeviceRect& aBounds)
     : mBuilder(&aBuilder),
       mScale(1.0f, 1.0f),
-      mDeferredTransformItem(aDeferredTransformItem),
-      mIsPreserve3D(aIsPreserve3D),
-      mRasterizeLocally(aAnimated || aParentSC.mRasterizeLocally) {
+      mDeferredTransformItem(aParams.mDeferredTransformItem),
+      mIsPreserve3D(aParams.transform_style == wr::TransformStyle::Preserve3D),
+      mRasterizeLocally(aParams.mAnimated || aParentSC.mRasterizeLocally) {
   // Compute scale for fallback rendering. We don't try to guess a scale for 3d
   // transformed items
   gfx::Matrix transform2d;
-  if (aBoundTransform && aBoundTransform->CanDraw2D(&transform2d) &&
-      aReferenceFrameKind != wr::ReferenceFrameKind::Perspective &&
+  if (aParams.mBoundTransform &&
+      aParams.mBoundTransform->CanDraw2D(&transform2d) &&
+      aParams.reference_frame_kind != wr::ReferenceFrameKind::Perspective &&
       !aParentSC.mIsPreserve3D) {
     mInheritedTransform = transform2d * aParentSC.mInheritedTransform;
 
     int32_t apd = aContainerFrame->PresContext()->AppUnitsPerDevPixel();
     nsRect r = LayoutDevicePixel::ToAppUnits(aBounds, apd);
     mScale = FrameLayerBuilder::ChooseScale(aContainerFrame, aContainerItem, r,
                                             1.f, 1.f, mInheritedTransform,
                                             /* aCanDraw2D = */ true);
 
-    if (aAnimated) {
+    if (aParams.mAnimated) {
       mSnappingSurfaceTransform =
           gfx::Matrix::Scaling(mScale.width, mScale.height);
     } else {
       mSnappingSurfaceTransform =
           transform2d * aParentSC.mSnappingSurfaceTransform;
     }
   } else {
     mInheritedTransform = aParentSC.mInheritedTransform;
@@ -65,20 +59,17 @@ StackingContextHelper::StackingContextHe
   }
 
   auto rasterSpace =
       mRasterizeLocally
           ? wr::RasterSpace::Local(std::max(mScale.width, mScale.height))
           : wr::RasterSpace::Screen();
 
   mReferenceFrameId = mBuilder->PushStackingContext(
-      wr::ToLayoutRect(aBounds), aClip, aAnimation, aOpacityPtr, aTransformPtr,
-      aIsPreserve3D ? wr::TransformStyle::Preserve3D : wr::TransformStyle::Flat,
-      aReferenceFrameKind, wr::ToMixBlendMode(aMixBlendMode), aFilters,
-      aBackfaceVisible, rasterSpace);
+      aParams, wr::ToLayoutRect(aBounds), rasterSpace);
 
   if (mReferenceFrameId) {
     mSpaceAndClipChainHelper.emplace(aBuilder, mReferenceFrameId.ref());
   }
 
   mAffectsClipPositioning =
       mReferenceFrameId.isSome() || (aBounds.TopLeft() != LayoutDevicePoint());
 
--- a/gfx/layers/wr/StackingContextHelper.h
+++ b/gfx/layers/wr/StackingContextHelper.h
@@ -26,28 +26,19 @@ namespace layers {
  * some of the coordinate space transformations needed.
  */
 class MOZ_RAII StackingContextHelper {
  public:
   StackingContextHelper(
       const StackingContextHelper& aParentSC, const ActiveScrolledRoot* aAsr,
       nsIFrame* aContainerFrame, nsDisplayItem* aContainerItem,
       wr::DisplayListBuilder& aBuilder,
-      const nsTArray<wr::FilterOp>& aFilters = nsTArray<wr::FilterOp>(),
-      const LayoutDeviceRect& aBounds = LayoutDeviceRect(),
-      const gfx::Matrix4x4* aBoundTransform = nullptr,
-      const wr::WrAnimationProperty* aAnimation = nullptr,
-      const float* aOpacityPtr = nullptr,
-      const gfx::Matrix4x4* aTransformPtr = nullptr,
-      const wr::ReferenceFrameKind = wr::ReferenceFrameKind::Transform,
-      const gfx::CompositionOp& aMixBlendMode = gfx::CompositionOp::OP_OVER,
-      bool aBackfaceVisible = true, bool aIsPreserve3D = false,
-      const Maybe<nsDisplayTransform*>& aDeferredTransformItem = Nothing(),
-      const wr::WrStackingContextClip& = wr::WrStackingContextClip::None(),
-      bool aAnimated = false);
+      const wr::StackingContextParams& aParams = wr::StackingContextParams(),
+      const LayoutDeviceRect& aBounds = LayoutDeviceRect());
+
   // This version of the constructor should only be used at the root level
   // of the tree, so that we have a StackingContextHelper to pass down into
   // the RenderLayer traversal, but don't actually want it to push a stacking
   // context on the display list builder.
   StackingContextHelper();
 
   // Pops the stacking context, if one was pushed during the constructor.
   ~StackingContextHelper();
--- a/gfx/layers/wr/WebRenderCommandBuilder.cpp
+++ b/gfx/layers/wr/WebRenderCommandBuilder.cpp
@@ -1428,17 +1428,17 @@ void WebRenderCommandBuilder::EmptyTrans
 bool WebRenderCommandBuilder::NeedsEmptyTransaction() {
   return !mLastCanvasDatas.IsEmpty();
 }
 
 void WebRenderCommandBuilder::BuildWebRenderCommands(
     wr::DisplayListBuilder& aBuilder,
     wr::IpcResourceUpdateQueue& aResourceUpdates, nsDisplayList* aDisplayList,
     nsDisplayListBuilder* aDisplayListBuilder, WebRenderScrollData& aScrollData,
-    wr::LayoutSize& aContentSize, const nsTArray<wr::FilterOp>& aFilters) {
+    wr::LayoutSize& aContentSize, nsTArray<wr::FilterOp>&& aFilters) {
   StackingContextHelper sc;
   aScrollData = WebRenderScrollData(mManager);
   MOZ_ASSERT(mLayerScrollData.empty());
   mLastCanvasDatas.Clear();
   mLastAsr = nullptr;
   mBuilderDumpIndex = 0;
   mContainsSVGGroup = false;
   MOZ_ASSERT(mDumpIndent == 0);
@@ -1446,19 +1446,21 @@ void WebRenderCommandBuilder::BuildWebRe
 
   {
     if (!mZoomProp && gfxPrefs::APZAllowZooming() && XRE_IsContentProcess()) {
       mZoomProp.emplace();
       mZoomProp->effect_type = wr::WrAnimationType::Transform;
       mZoomProp->id = AnimationHelper::GetNextCompositorAnimationsId();
     }
 
+    wr::StackingContextParams params;
+    params.mFilters = std::move(aFilters);
+    params.animation = mZoomProp.ptrOr(nullptr);
     StackingContextHelper pageRootSc(sc, nullptr, nullptr, nullptr, aBuilder,
-                                     aFilters, LayoutDeviceRect(), nullptr,
-                                     mZoomProp.ptrOr(nullptr));
+                                     params);
     if (ShouldDumpDisplayList(aDisplayListBuilder)) {
       mBuilderDumpIndex =
           aBuilder.Dump(mDumpIndent + 1, Some(mBuilderDumpIndex), Nothing());
     }
     CreateWebRenderCommandsFromDisplayList(aDisplayList, nullptr,
                                            aDisplayListBuilder, pageRootSc,
                                            aBuilder, aResourceUpdates);
   }
--- a/gfx/layers/wr/WebRenderCommandBuilder.h
+++ b/gfx/layers/wr/WebRenderCommandBuilder.h
@@ -52,17 +52,17 @@ class WebRenderCommandBuilder {
   bool NeedsEmptyTransaction();
 
   void BuildWebRenderCommands(wr::DisplayListBuilder& aBuilder,
                               wr::IpcResourceUpdateQueue& aResourceUpdates,
                               nsDisplayList* aDisplayList,
                               nsDisplayListBuilder* aDisplayListBuilder,
                               WebRenderScrollData& aScrollData,
                               wr::LayoutSize& aContentSize,
-                              const nsTArray<wr::FilterOp>& aFilters);
+                              nsTArray<wr::FilterOp>&& aFilters);
 
   void PushOverrideForASR(const ActiveScrolledRoot* aASR,
                           const wr::WrSpatialId& aSpatialId);
   void PopOverrideForASR(const ActiveScrolledRoot* aASR);
 
   Maybe<wr::ImageKey> CreateImageKey(
       nsDisplayItem* aItem, ImageContainer* aContainer,
       mozilla::wr::DisplayListBuilder& aBuilder,
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -241,18 +241,17 @@ void WebRenderLayerManager::EndTransacti
                                            EndTransactionFlags aFlags) {
   // This should never get called, all callers should use
   // EndTransactionWithoutLayer instead.
   MOZ_ASSERT(false);
 }
 
 void WebRenderLayerManager::EndTransactionWithoutLayer(
     nsDisplayList* aDisplayList, nsDisplayListBuilder* aDisplayListBuilder,
-    const nsTArray<wr::FilterOp>& aFilters,
-    WebRenderBackgroundData* aBackground) {
+    nsTArray<wr::FilterOp>&& aFilters, WebRenderBackgroundData* aBackground) {
   AUTO_PROFILER_TRACING("Paint", "RenderLayers", GRAPHICS);
 
   // Since we don't do repeat transactions right now, just set the time
   mAnimationReadyTime = TimeStamp::Now();
 
   WrBridge()->BeginTransaction();
 
   LayoutDeviceIntSize size = mWidget->GetClientSize();
@@ -271,17 +270,17 @@ void WebRenderLayerManager::EndTransacti
   if (aDisplayList) {
     MOZ_ASSERT(aDisplayListBuilder && !aBackground);
     // Record the time spent "layerizing". WR doesn't actually layerize but
     // generating the WR display list is the closest equivalent
     PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::Layerization);
 
     mWebRenderCommandBuilder.BuildWebRenderCommands(
         builder, resourceUpdates, aDisplayList, aDisplayListBuilder,
-        mScrollData, contentSize, aFilters);
+        mScrollData, contentSize, std::move(aFilters));
     builderDumpIndex = mWebRenderCommandBuilder.GetBuilderDumpIndex();
     containsSVGGroup = mWebRenderCommandBuilder.GetContainsSVGGroup();
   } else {
     // ViewToPaint does not have frame yet, then render only background clolor.
     MOZ_ASSERT(!aDisplayListBuilder && aBackground);
     aBackground->AddWebRenderCommands(builder);
     if (dumpEnabled) {
       printf_stderr("(no display list; background only)\n");
--- a/gfx/layers/wr/WebRenderLayerManager.h
+++ b/gfx/layers/wr/WebRenderLayerManager.h
@@ -74,17 +74,17 @@ class WebRenderLayerManager final : publ
 
   virtual bool BeginTransactionWithTarget(gfxContext* aTarget,
                                           const nsCString& aURL) override;
   virtual bool BeginTransaction(const nsCString& aURL) override;
   virtual bool EndEmptyTransaction(
       EndTransactionFlags aFlags = END_DEFAULT) override;
   void EndTransactionWithoutLayer(
       nsDisplayList* aDisplayList, nsDisplayListBuilder* aDisplayListBuilder,
-      const nsTArray<wr::FilterOp>& aFilters = nsTArray<wr::FilterOp>(),
+      nsTArray<wr::FilterOp>&& aFilters = nsTArray<wr::FilterOp>(),
       WebRenderBackgroundData* aBackground = nullptr);
   virtual void EndTransaction(
       DrawPaintedLayerCallback aCallback, void* aCallbackData,
       EndTransactionFlags aFlags = END_DEFAULT) override;
 
   virtual LayersBackend GetBackendType() override {
     return LayersBackend::LAYERS_WR;
   }
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -668,39 +668,34 @@ usize DisplayListBuilder::Dump(usize aIn
 
 void DisplayListBuilder::Finalize(wr::LayoutSize& aOutContentSize,
                                   BuiltDisplayList& aOutDisplayList) {
   wr_api_finalize_builder(mWrState, &aOutContentSize, &aOutDisplayList.dl_desc,
                           &aOutDisplayList.dl.inner);
 }
 
 Maybe<wr::WrSpatialId> DisplayListBuilder::PushStackingContext(
-    const wr::LayoutRect& aBounds, const wr::WrStackingContextClip& aClip,
-    const WrAnimationProperty* aAnimation, const float* aOpacity,
-    const gfx::Matrix4x4* aTransform, wr::TransformStyle aTransformStyle,
-    const wr::ReferenceFrameKind aReferenceFrameKind,
-    const wr::MixBlendMode& aMixBlendMode,
-    const nsTArray<wr::FilterOp>& aFilters, bool aIsBackfaceVisible,
+    const wr::StackingContextParams& aParams, const wr::LayoutRect& aBounds,
     const wr::RasterSpace& aRasterSpace) {
   MOZ_ASSERT(mClipChainLeaf.isNothing(),
              "Non-empty leaf from clip chain given, but not used with SC!");
 
   wr::LayoutTransform matrix;
-  if (aTransform) {
-    matrix = ToLayoutTransform(*aTransform);
+  const gfx::Matrix4x4* transform = aParams.mTransformPtr;
+  if (transform) {
+    matrix = ToLayoutTransform(*transform);
   }
-  const wr::LayoutTransform* maybeTransform = aTransform ? &matrix : nullptr;
+  const wr::LayoutTransform* maybeTransform = transform ? &matrix : nullptr;
   WRDL_LOG("PushStackingContext b=%s t=%s\n", mWrState,
            Stringify(aBounds).c_str(),
-           aTransform ? Stringify(*aTransform).c_str() : "none");
+           transform ? Stringify(*transform).c_str() : "none");
 
   auto spatialId = wr_dp_push_stacking_context(
-      mWrState, aBounds, mCurrentSpaceAndClipChain.space, &aClip, aAnimation,
-      aOpacity, maybeTransform, aTransformStyle, aReferenceFrameKind,
-      aMixBlendMode, aFilters.Elements(), aFilters.Length(), aIsBackfaceVisible,
+      mWrState, aBounds, mCurrentSpaceAndClipChain.space, &aParams,
+      maybeTransform, aParams.mFilters.Elements(), aParams.mFilters.Length(),
       aRasterSpace);
 
   return spatialId.id != 0 ? Some(spatialId) : Nothing();
 }
 
 void DisplayListBuilder::PopStackingContext(bool aIsReferenceFrame) {
   WRDL_LOG("PopStackingContext\n", mWrState);
   wr_dp_pop_stacking_context(mWrState, aIsReferenceFrame);
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -18,16 +18,17 @@
 #include "mozilla/layers/SyncObject.h"
 #include "mozilla/Range.h"
 #include "mozilla/webrender/webrender_ffi.h"
 #include "mozilla/webrender/WebRenderTypes.h"
 #include "GLTypes.h"
 #include "Units.h"
 
 class nsDisplayItem;
+class nsDisplayTransform;
 
 namespace mozilla {
 
 struct ActiveScrolledRoot;
 
 namespace widget {
 class CompositorWidget;
 }
@@ -302,16 +303,42 @@ class MOZ_RAII AutoTransactionSender {
 
   ~AutoTransactionSender() { mApi->SendTransaction(*mTxn); }
 
  private:
   WebRenderAPI* mApi;
   TransactionBuilder* mTxn;
 };
 
+/**
+ * A set of optional parameters for stacking context creation.
+ */
+struct MOZ_STACK_CLASS StackingContextParams : public WrStackingContextParams {
+  StackingContextParams()
+      : WrStackingContextParams{WrStackingContextClip::None(),
+                                nullptr,
+                                nullptr,
+                                wr::TransformStyle::Flat,
+                                wr::ReferenceFrameKind::Transform,
+                                /* is_backface_visible = */ true,
+                                wr::MixBlendMode::Normal} {}
+
+  void SetPreserve3D(bool aPreserve) {
+    transform_style =
+        aPreserve ? wr::TransformStyle::Preserve3D : wr::TransformStyle::Flat;
+  }
+
+  nsTArray<wr::FilterOp> mFilters;
+  wr::LayoutRect mBounds = wr::ToLayoutRect(LayoutDeviceRect());
+  const gfx::Matrix4x4* mBoundTransform = nullptr;
+  const gfx::Matrix4x4* mTransformPtr = nullptr;
+  Maybe<nsDisplayTransform*> mDeferredTransformItem;
+  bool mAnimated = false;
+};
+
 /// This is a simple C++ wrapper around WrState defined in the rust bindings.
 /// We may want to turn this into a direct wrapper on top of
 /// WebRenderFrameBuilder instead, so the interface may change a bit.
 class DisplayListBuilder {
  public:
   explicit DisplayListBuilder(wr::PipelineId aId,
                               const wr::LayoutSize& aContentSize,
                               size_t aCapacity = 0);
@@ -324,22 +351,17 @@ class DisplayListBuilder {
   void ClearSave();
   usize Dump(usize aIndent, const Maybe<usize>& aStart,
              const Maybe<usize>& aEnd);
 
   void Finalize(wr::LayoutSize& aOutContentSize,
                 wr::BuiltDisplayList& aOutDisplayList);
 
   Maybe<wr::WrSpatialId> PushStackingContext(
-      // TODO: We should work with strongly typed rects
-      const wr::LayoutRect& aBounds, const wr::WrStackingContextClip& aClip,
-      const wr::WrAnimationProperty* aAnimation, const float* aOpacity,
-      const gfx::Matrix4x4* aTransform, wr::TransformStyle aTransformStyle,
-      const wr::ReferenceFrameKind, const wr::MixBlendMode& aMixBlendMode,
-      const nsTArray<wr::FilterOp>& aFilters, bool aIsBackfaceVisible,
+      const StackingContextParams& aParams, const wr::LayoutRect& aBounds,
       const wr::RasterSpace& aRasterSpace);
   void PopStackingContext(bool aIsReferenceFrame);
 
   wr::WrClipChainId DefineClipChain(const Maybe<wr::WrClipChainId>& aParent,
                                     const nsTArray<wr::WrClipId>& aClips);
 
   wr::WrClipId DefineClip(
       const Maybe<wr::WrSpaceAndClip>& aParent, const wr::LayoutRect& aClipRect,
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -1890,49 +1890,56 @@ pub extern "C" fn wr_dp_restore(state: &
     state.frame_builder.dl_builder.restore();
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_clear_save(state: &mut WrState) {
     state.frame_builder.dl_builder.clear_save();
 }
 
+/// IMPORTANT: If you add fields to this struct, you need to also add initializers
+/// for those fields in WebRenderAPI.h.
+#[repr(C)]
+pub struct WrStackingContextParams {
+    pub clip: WrStackingContextClip,
+    pub animation: *const WrAnimationProperty,
+    pub opacity: *const f32,
+    pub transform_style: TransformStyle,
+    pub reference_frame_kind: ReferenceFrameKind,
+    pub is_backface_visible: bool,
+    pub mix_blend_mode: MixBlendMode,
+}
+
 #[no_mangle]
 pub extern "C" fn wr_dp_push_stacking_context(
     state: &mut WrState,
     mut bounds: LayoutRect,
     spatial_id: WrSpatialId,
-    clip: &WrStackingContextClip,
-    animation: *const WrAnimationProperty,
-    opacity: *const f32,
+    params: &WrStackingContextParams,
     transform: *const LayoutTransform,
-    transform_style: TransformStyle,
-    reference_frame_kind: ReferenceFrameKind,
-    mix_blend_mode: MixBlendMode,
     filters: *const FilterOp,
     filter_count: usize,
-    is_backface_visible: bool,
     glyph_raster_space: RasterSpace,
 ) -> WrSpatialId {
     debug_assert!(unsafe { !is_in_render_thread() });
 
     let c_filters = make_slice(filters, filter_count);
     let mut filters : Vec<FilterOp> = c_filters.iter().map(|c_filter| {
                                                            *c_filter
     }).collect();
 
     let transform_ref = unsafe { transform.as_ref() };
     let mut transform_binding = match transform_ref {
-        Some(transform) => Some(PropertyBinding::Value(transform.clone())),
+        Some(t) => Some(PropertyBinding::Value(t.clone())),
         None => None,
     };
 
-    let opacity_ref = unsafe { opacity.as_ref() };
+    let opacity_ref = unsafe { params.opacity.as_ref() };
     let mut has_opacity_animation = false;
-    let anim = unsafe { animation.as_ref() };
+    let anim = unsafe { params.animation.as_ref() };
     if let Some(anim) = anim {
         debug_assert!(anim.id > 0);
         match anim.effect_type {
             WrAnimationType::Opacity => {
                 filters.push(FilterOp::Opacity(PropertyBinding::Binding(PropertyBindingKey::new(anim.id),
                                                                         // We have to set the static opacity value as
                                                                         // the value for the case where the animation is
                                                                         // in not in-effect (e.g. in the delay phase
@@ -1952,50 +1959,50 @@ pub extern "C" fn wr_dp_push_stacking_co
 
     if let Some(opacity) = opacity_ref {
         if !has_opacity_animation && *opacity < 1.0 {
             filters.push(FilterOp::Opacity(PropertyBinding::Value(*opacity), *opacity));
         }
     }
 
     let mut wr_spatial_id = spatial_id.to_webrender(state.pipeline_id);
-    let wr_clip_id = clip.to_webrender(state.pipeline_id);
+    let wr_clip_id = params.clip.to_webrender(state.pipeline_id);
 
     // Note: 0 has special meaning in WR land, standing for ROOT_REFERENCE_FRAME.
     // However, it is never returned by `push_reference_frame`, and we need to return
     // an option here across FFI, so we take that 0 value for the None semantics.
     // This is resolved into proper `Maybe<WrSpatialId>` inside `WebRenderAPI::PushStackingContext`.
     let mut result = WrSpatialId { id: 0 };
     if let Some(transform_binding) = transform_binding {
         wr_spatial_id = state.frame_builder.dl_builder.push_reference_frame(
             &bounds,
             wr_spatial_id,
-            transform_style,
+            params.transform_style,
             transform_binding,
-            reference_frame_kind,
+            params.reference_frame_kind,
         );
 
         bounds.origin = LayoutPoint::zero();
         result.id = wr_spatial_id.0;
         assert_ne!(wr_spatial_id.0, 0);
     }
 
     let prim_info = LayoutPrimitiveInfo {
-        is_backface_visible,
+        is_backface_visible: params.is_backface_visible,
         tag: state.current_tag,
         .. LayoutPrimitiveInfo::new(bounds)
     };
 
     state.frame_builder
          .dl_builder
          .push_stacking_context(&prim_info,
                                 wr_spatial_id,
                                 wr_clip_id,
-                                transform_style,
-                                mix_blend_mode,
+                                params.transform_style,
+                                params.mix_blend_mode,
                                 &filters,
                                 glyph_raster_space);
 
     result
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_pop_stacking_context(state: &mut WrState,
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -6095,17 +6095,17 @@ void PresShell::Paint(nsView* aViewToPai
         pc->GetVisibleArea(), pc->AppUnitsPerDevPixel());
     bgcolor = NS_ComposeColors(bgcolor, mCanvasBackgroundColor);
     WebRenderBackgroundData data(wr::ToLayoutRect(bounds),
                                  wr::ToColorF(ToDeviceColor(bgcolor)));
     nsTArray<wr::FilterOp> wrFilters;
 
     MaybeSetupTransactionIdAllocator(layerManager, presContext);
     layerManager->AsWebRenderLayerManager()->EndTransactionWithoutLayer(
-        nullptr, nullptr, wrFilters, &data);
+        nullptr, nullptr, std::move(wrFilters), &data);
     return;
   }
 
   RefPtr<ColorLayer> root = layerManager->CreateColorLayer();
   if (root) {
     nsPresContext* pc = GetPresContext();
     nsIntRect bounds =
         pc->GetVisibleArea().ToOutsidePixels(pc->AppUnitsPerDevPixel());
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -2623,17 +2623,18 @@ already_AddRefed<LayerManager> nsDisplay
       nsTArray<wr::FilterOp> wrFilters;
       gfx::Matrix5x4* colorMatrix =
           nsDocShell::Cast(docShell)->GetColorMatrix();
       if (colorMatrix) {
         wrFilters.AppendElement(
             wr::FilterOp::ColorMatrix(colorMatrix->components));
       }
 
-      wrManager->EndTransactionWithoutLayer(this, aBuilder, wrFilters);
+      wrManager->EndTransactionWithoutLayer(this, aBuilder,
+                                            std::move(wrFilters));
     }
 
     // For layers-free mode, we check the invalidation state bits in the
     // EndTransaction. So we clear the invalidation state bits after
     // EndTransaction.
     if (widgetTransaction ||
         // SVG-as-an-image docs don't paint as part of the retained layer tree,
         // but they still need the invalidation state bits cleared in order for
@@ -6071,20 +6072,21 @@ bool nsDisplayOpacity::CreateWebRenderCo
 
   uint64_t animationsId = AddAnimationsForWebRender(
       this, eCSSProperty_opacity, aManager, aDisplayListBuilder);
   wr::WrAnimationProperty prop{
       wr::WrAnimationType::Opacity,
       animationsId,
   };
 
-  nsTArray<mozilla::wr::FilterOp> filters;
+  wr::StackingContextParams params;
+  params.animation = animationsId ? &prop : nullptr;
+  params.opacity = opacityForSC;
   StackingContextHelper sc(aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder,
-                           filters, LayoutDeviceRect(), nullptr,
-                           animationsId ? &prop : nullptr, opacityForSC);
+                           params);
 
   aManager->CommandBuilder().CreateWebRenderCommandsFromDisplayList(
       &mList, this, aDisplayListBuilder, sc, aBuilder, aResources);
   return true;
 }
 
 nsDisplayBlendMode::nsDisplayBlendMode(
     nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList,
@@ -6110,21 +6112,21 @@ LayerState nsDisplayBlendMode::GetLayerS
 }
 
 bool nsDisplayBlendMode::CreateWebRenderCommands(
     mozilla::wr::DisplayListBuilder& aBuilder,
     mozilla::wr::IpcResourceUpdateQueue& aResources,
     const StackingContextHelper& aSc,
     mozilla::layers::RenderRootStateManager* aManager,
     nsDisplayListBuilder* aDisplayListBuilder) {
-  nsTArray<mozilla::wr::FilterOp> filters;
+  wr::StackingContextParams params;
+  params.mix_blend_mode =
+      wr::ToMixBlendMode(nsCSSRendering::GetGFXBlendMode(mBlendMode));
   StackingContextHelper sc(aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder,
-                           filters, LayoutDeviceRect(), nullptr, nullptr,
-                           nullptr, nullptr, wr::ReferenceFrameKind::Transform,
-                           nsCSSRendering::GetGFXBlendMode(mBlendMode));
+                           params);
 
   return nsDisplayWrapList::CreateWebRenderCommands(
       aBuilder, aResources, sc, aManager, aDisplayListBuilder);
 }
 
 // nsDisplayBlendMode uses layers for rendering
 already_AddRefed<Layer> nsDisplayBlendMode::BuildLayer(
     nsDisplayListBuilder* aBuilder, LayerManager* aManager,
@@ -6341,19 +6343,21 @@ bool nsDisplayOwnLayer::CreateWebRenderC
   AnimationInfo& animationInfo = animationData->GetAnimationInfo();
   animationInfo.EnsureAnimationsId();
   mWrAnimationId = animationInfo.GetCompositorAnimationsId();
 
   wr::WrAnimationProperty prop;
   prop.id = mWrAnimationId;
   prop.effect_type = wr::WrAnimationType::Transform;
 
+  wr::StackingContextParams params;
+  params.animation = &prop;
+
   StackingContextHelper sc(aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder,
-                           nsTArray<wr::FilterOp>(), LayoutDeviceRect(),
-                           nullptr, &prop);
+                           params);
 
   nsDisplayWrapList::CreateWebRenderCommands(aBuilder, aResources, sc, aManager,
                                              aDisplayListBuilder);
   return true;
 }
 
 bool nsDisplayOwnLayer::UpdateScrollData(
     mozilla::layers::WebRenderScrollData* aData,
@@ -7873,41 +7877,43 @@ bool nsDisplayTransform::CreateWebRender
 
   uint64_t animationsId = AddAnimationsForWebRender(
       this, eCSSProperty_transform, aManager, aDisplayListBuilder);
   wr::WrAnimationProperty prop{
       wr::WrAnimationType::Transform,
       animationsId,
   };
 
-  nsTArray<mozilla::wr::FilterOp> filters;
   Maybe<nsDisplayTransform*> deferredTransformItem;
   if (!mFrame->ChildrenHavePerspective()) {
     // If it has perspective, we create a new scroll data via the
     // UpdateScrollData call because that scenario is more complex. Otherwise
     // we can just stash the transform on the StackingContextHelper and
     // apply it to any scroll data that are created inside this
     // nsDisplayTransform.
     deferredTransformItem = Some(this);
   }
 
   // If it looks like we're animated, we should rasterize in local space
   // (disabling subpixel-aa and global pixel snapping)
   bool animated =
       ActiveLayerTracker::IsStyleMaybeAnimated(Frame(), eCSSProperty_transform);
 
-  bool preserve3D = mFrame->Extend3DContext() && !mIsTransformSeparator;
-
-  StackingContextHelper sc(
-      aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder, filters,
-      LayoutDeviceRect(position, LayoutDeviceSize()), &newTransformMatrix,
-      animationsId ? &prop : nullptr, nullptr, transformForSC,
-      wr::ReferenceFrameKind::Transform, gfx::CompositionOp::OP_OVER,
-      !BackfaceIsHidden(), preserve3D, deferredTransformItem,
-      wr::WrStackingContextClip::None(), animated);
+  wr::StackingContextParams params;
+  params.mBoundTransform = &newTransformMatrix;
+  params.animation = animationsId ? &prop : nullptr;
+  params.mTransformPtr = transformForSC;
+  params.is_backface_visible = !BackfaceIsHidden();
+  params.mDeferredTransformItem = deferredTransformItem;
+  params.mAnimated = animated;
+  params.SetPreserve3D(mFrame->Extend3DContext() && !mIsTransformSeparator);
+
+  StackingContextHelper sc(aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder,
+                           params,
+                           LayoutDeviceRect(position, LayoutDeviceSize()));
 
   return mStoredList.CreateWebRenderCommands(aBuilder, aResources, sc, aManager,
                                              aDisplayListBuilder);
 }
 
 bool nsDisplayTransform::UpdateScrollData(
     mozilla::layers::WebRenderScrollData* aData,
     mozilla::layers::WebRenderLayerScrollData* aLayerData) {
@@ -8496,22 +8502,24 @@ bool nsDisplayPerspective::CreateWebRend
   // WR knows how to treat perspective in that case, so the only thing we need
   // to do is to ensure we pass true when we're involved in a 3d context in any
   // other way via the transform-style property on either the transformed frame
   // or the perspective frame in order to not confuse WR's preserve-3d code in
   // very awful ways.
   bool preserve3D =
       mFrame->Extend3DContext() || perspectiveFrame->Extend3DContext();
 
-  nsTArray<mozilla::wr::FilterOp> filters;
-  StackingContextHelper sc(
-      aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder, filters,
-      LayoutDeviceRect(), nullptr, nullptr, nullptr, &perspectiveMatrix,
-      wr::ReferenceFrameKind::Perspective, gfx::CompositionOp::OP_OVER,
-      !BackfaceIsHidden(), preserve3D);
+  wr::StackingContextParams params;
+  params.mTransformPtr = &perspectiveMatrix;
+  params.reference_frame_kind = wr::ReferenceFrameKind::Perspective;
+  params.is_backface_visible = !BackfaceIsHidden();
+  params.SetPreserve3D(preserve3D);
+
+  StackingContextHelper sc(aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder,
+                           params);
 
   return mList.CreateWebRenderCommands(aBuilder, aResources, sc, aManager,
                                        aDisplayListBuilder);
 }
 
 nsDisplayItemGeometry* nsCharClipDisplayItem::AllocateGeometry(
     nsDisplayListBuilder* aBuilder) {
   return new nsCharClipGeometry(this, aBuilder);
@@ -9092,29 +9100,21 @@ bool nsDisplayMasksAndClipPaths::CreateW
     bounds.MoveTo(0, 0);
 
     wr::WrClipId clipId = clip->first();
 
     Maybe<float> opacity = clip->second() == HandleOpacity::Yes
                                ? Some(mFrame->StyleEffects()->mOpacity)
                                : Nothing();
 
-    layer.emplace(aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder,
-                  /*aFilters: */ nsTArray<wr::FilterOp>(),
-                  /*aBounds: */ bounds,
-                  /*aBoundTransform: */ nullptr,
-                  /*aAnimation: */ nullptr,
-                  /*aOpacity: */ opacity.ptrOr(nullptr),
-                  /*aTransform: */ nullptr,
-                  /*aReferenceFrameKind: */ wr::ReferenceFrameKind::Transform,
-                  /*aMixBlendMode: */ gfx::CompositionOp::OP_OVER,
-                  /*aBackfaceVisible: */ true,
-                  /*aIsPreserve3D: */ false,
-                  /*aTransformForScrollData: */ Nothing(),
-                  /*aClip: */ wr::WrStackingContextClip::ClipId(clipId));
+    wr::StackingContextParams params;
+    params.clip = wr::WrStackingContextClip::ClipId(clipId);
+    params.opacity = opacity.ptrOr(nullptr);
+    layer.emplace(aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder, params,
+                  bounds);
     sc = layer.ptr();
   }
 
   nsDisplayEffectsBase::CreateWebRenderCommands(aBuilder, aResources, *sc,
                                                 aManager, aDisplayListBuilder);
 
   return true;
 }
@@ -9408,22 +9408,22 @@ bool nsDisplayFilters::CreateWebRenderCo
     wr::WrClipId clipId =
         aBuilder.DefineClip(Nothing(), wr::ToRoundedLayoutRect(devPxRect));
     clip = wr::WrStackingContextClip::ClipId(clipId);
   } else {
     clip = wr::WrStackingContextClip::ClipChain(aBuilder.CurrentClipChainId());
   }
 
   float opacity = mFrame->StyleEffects()->mOpacity;
-  StackingContextHelper sc(
-      aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder, wrFilters,
-      LayoutDeviceRect(), nullptr, nullptr,
-      opacity != 1.0f && mHandleOpacity ? &opacity : nullptr, nullptr,
-      wr::ReferenceFrameKind::Transform, gfx::CompositionOp::OP_OVER, true,
-      false, Nothing(), clip);
+  wr::StackingContextParams params;
+  params.mFilters = std::move(wrFilters);
+  params.opacity = opacity != 1.0f && mHandleOpacity ? &opacity : nullptr;
+  params.clip = clip;
+  StackingContextHelper sc(aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder,
+                           params);
 
   nsDisplayEffectsBase::CreateWebRenderCommands(aBuilder, aResources, sc,
                                                 aManager, aDisplayListBuilder);
 
   return true;
 }
 
 #ifdef MOZ_DUMP_PAINTING