Bug 1339661 - Create box shadow outer webrender display item. r=jmuizelaar
authorMason Chang <mchang@mozilla.com>
Thu, 16 Feb 2017 10:23:22 -0800
changeset 343982 687b3bd601ba93cf746f2ef1cd3af2c60f7d2128
parent 343981 9a03f0308986482929af1f6cf62c0edcd957ea73
child 343983 ae5c9d27cc3cb7e309b9b21d12a4c338a5de82a0
push id31395
push userkwierso@gmail.com
push dateTue, 21 Feb 2017 18:17:00 +0000
treeherdermozilla-central@c7b015c488cf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjmuizelaar
bugs1339661
milestone54.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 1339661 - Create box shadow outer webrender display item. r=jmuizelaar
gfx/layers/ipc/WebRenderMessages.ipdlh
gfx/layers/moz.build
gfx/layers/wr/WebRenderBridgeParent.cpp
gfx/layers/wr/WebRenderMessageUtils.h
gfx/thebes/gfxPrefs.h
gfx/webrender_bindings/WebRenderAPI.cpp
gfx/webrender_bindings/WebRenderAPI.h
gfx/webrender_bindings/src/bindings.rs
gfx/webrender_bindings/webrender_ffi.h
layout/painting/nsDisplayList.cpp
layout/painting/nsDisplayList.h
--- a/gfx/layers/ipc/WebRenderMessages.ipdlh
+++ b/gfx/layers/ipc/WebRenderMessages.ipdlh
@@ -9,18 +9,20 @@ include LayersSurfaces;
 include LayersMessages;
 include protocol PTexture;
 
 using WrBorderRadius from "mozilla/webrender/webrender_ffi.h";
 using WrBorderSide from "mozilla/webrender/webrender_ffi.h";
 using WrColor from "mozilla/webrender/webrender_ffi.h";
 using WrLayoutSize from "mozilla/webrender/webrender_ffi.h";
 using WrRect from "mozilla/webrender/webrender_ffi.h";
+using WrPoint from "mozilla/webrender/webrender_ffi.h";
 using WrGlyphArray from "mozilla/webrender/webrender_ffi.h";
 using WrMixBlendMode from "mozilla/webrender/webrender_ffi.h";
+using WrBoxShadowClipMode from "mozilla/webrender/webrender_ffi.h";
 using MaybeImageMask from "mozilla/webrender/WebRenderTypes.h";
 using mozilla::gfx::Matrix4x4 from "mozilla/gfx/Matrix.h";
 using mozilla::wr::ByteBuffer from "mozilla/webrender/WebRenderTypes.h";
 using mozilla::wr::PipelineId from "mozilla/webrender/WebRenderTypes.h";
 using mozilla::wr::ImageRendering from "mozilla/webrender/WebRenderTypes.h";
 using mozilla::wr::ImageKey from "mozilla/webrender/WebRenderTypes.h";
 using mozilla::LayerIntRegion from "Units.h";
 
@@ -93,24 +95,37 @@ struct OpDPPushText {
   WrRect clip;
   WrGlyphArray[] glyph_array;
   uint32_t font_index;
   float glyph_size;
   ByteBuffer font_buffer;
   uint32_t font_buffer_length;
 };
 
+struct OpDPPushBoxShadow {
+  WrRect rect;
+  WrRect clip;
+  WrRect box_bounds;
+  WrPoint offset;
+  WrColor color;
+  float blur_radius;
+  float spread_radius;
+  float border_radius;
+  WrBoxShadowClipMode clip_mode;
+};
+
 union WebRenderCommand {
   OpDPPushStackingContext;
   OpDPPopStackingContext;
   OpDPPushScrollLayer;
   OpDPPopScrollLayer;
   OpDPPushRect;
   OpDPPushBorder;
   OpDPPushImage;
   OpDPPushExternalImageId;
   OpDPPushIframe;
   OpDPPushText;
+  OpDPPushBoxShadow;
   CompositableOperation;
 };
 
 } // namespace
 } // namespace
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -205,16 +205,17 @@ EXPORTS.mozilla.layers += [
     'RenderTrace.h',
     'SourceSurfaceSharedData.h',
     'SourceSurfaceVolatileData.h',
     'TextureWrapperImage.h',
     'TransactionIdAllocator.h',
     'wr/WebRenderBridgeChild.h',
     'wr/WebRenderBridgeParent.h',
     'wr/WebRenderCompositableHolder.h',
+    'wr/WebRenderDisplayItemLayer.h',
     'wr/WebRenderImageHost.h',
     'wr/WebRenderLayerManager.h',
     'wr/WebRenderLayersLogging.h',
     'wr/WebRenderMessageUtils.h',
 ]
 
 if CONFIG['MOZ_X11']:
     EXPORTS.mozilla.layers += [
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -370,16 +370,29 @@ WebRenderBridgeParent::ProcessWebrenderC
                            glyph_array[i].color,
                            fontKey,
                            Range<const WrGlyphInstance>(glyphs.Elements(), glyphs.Length()),
                            op.glyph_size());
         }
 
         break;
       }
+      case WebRenderCommand::TOpDPPushBoxShadow: {
+        const OpDPPushBoxShadow& op = cmd.get_OpDPPushBoxShadow();
+        builder.PushBoxShadow(op.rect(),
+                              op.clip(),
+                              op.box_bounds(),
+                              op.offset(),
+                              op.color(),
+                              op.blur_radius(),
+                              op.spread_radius(),
+                              op.border_radius(),
+                              op.clip_mode());
+        break;
+      }
       default:
         NS_RUNTIMEABORT("not reached");
     }
   }
   builder.End(*mApi, aEpoch);
 
   ScheduleComposition();
   DeleteOldImages();
--- a/gfx/layers/wr/WebRenderMessageUtils.h
+++ b/gfx/layers/wr/WebRenderMessageUtils.h
@@ -267,16 +267,34 @@ struct ParamTraits<WrRect>
     return ReadParam(aMsg, aIter, &aResult->x)
         && ReadParam(aMsg, aIter, &aResult->y)
         && ReadParam(aMsg, aIter, &aResult->width)
         && ReadParam(aMsg, aIter, &aResult->height);
   }
 };
 
 template<>
+struct ParamTraits<WrPoint>
+{
+  static void
+  Write(Message* aMsg, const WrPoint& aParam)
+  {
+    WriteParam(aMsg, aParam.x);
+    WriteParam(aMsg, aParam.y);
+  }
+
+  static bool
+  Read(const Message* aMsg, PickleIterator* aIter, WrPoint* aResult)
+  {
+    return ReadParam(aMsg, aIter, &aResult->x) &&
+           ReadParam(aMsg, aIter, &aResult->y);
+  }
+};
+
+template<>
 struct ParamTraits<WrImageMask>
 {
   static void
   Write(Message* aMsg, const WrImageMask& aParam)
   {
     WriteParam(aMsg, aParam.image);
     WriteParam(aMsg, aParam.rect);
     WriteParam(aMsg, aParam.repeat);
@@ -304,11 +322,20 @@ template<>
 struct ParamTraits<WrMixBlendMode>
   : public ContiguousEnumSerializer<
         WrMixBlendMode,
         WrMixBlendMode::Normal,
         WrMixBlendMode::Sentinel>
 {
 };
 
+template<>
+struct ParamTraits<WrBoxShadowClipMode>
+  : public ContiguousEnumSerializer<
+        WrBoxShadowClipMode,
+        WrBoxShadowClipMode::None,
+        WrBoxShadowClipMode::Sentinel>
+{
+};
+
 } // namespace IPC
 
 #endif // GFX_WEBRENDERMESSAGEUTILS_H
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -451,16 +451,17 @@ private:
   DECL_GFX_PREF(Live, "layers.acceleration.draw-fps",          LayersDrawFPS, bool, false);
   DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.print-histogram",  FPSPrintHistogram, bool, false);
   DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.write-to-file", WriteFPSToFile, bool, false);
   DECL_GFX_PREF(Once, "layers.acceleration.force-enabled",     LayersAccelerationForceEnabledDoNotUseDirectly, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.border-layers",         LayersAllowBorderLayers, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.text-layers",           LayersAllowTextLayers, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.bullet-layers",         LayersAllowBulletLayers, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.caret-layers",          LayersAllowCaretLayers, bool, false);
+  DECL_GFX_PREF(Live, "layers.advanced.boxshadow-outer-layers", LayersAllowOuterBoxShadow, bool, false);
   DECL_GFX_PREF(Once, "layers.allow-d3d9-fallback",            LayersAllowD3D9Fallback, bool, false);
   DECL_GFX_PREF(Once, "layers.amd-switchable-gfx.enabled",     LayersAMDSwitchableGfxEnabled, bool, false);
   DECL_GFX_PREF(Once, "layers.async-pan-zoom.enabled",         AsyncPanZoomEnabledDoNotUseDirectly, bool, true);
   DECL_GFX_PREF(Once, "layers.async-pan-zoom.separate-event-thread", AsyncPanZoomSeparateEventThread, bool, false);
   DECL_GFX_PREF(Live, "layers.bench.enabled",                  LayersBenchEnabled, bool, false);
   DECL_GFX_PREF(Once, "layers.bufferrotation.enabled",         BufferRotationEnabled, bool, true);
   DECL_GFX_PREF(Live, "layers.child-process-shutdown",         ChildProcessShutdown, bool, true);
 #ifdef MOZ_GFX_OPTIMIZE_MOBILE
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -399,10 +399,27 @@ DisplayListBuilder::PushText(const WrRec
 {
   wr_dp_push_text(mWrState, aBounds, aClip,
                   ToWrColor(aColor),
                   aFontKey,
                   &aGlyphBuffer[0], aGlyphBuffer.length(),
                   aGlyphSize);
 }
 
+void
+DisplayListBuilder::PushBoxShadow(const WrRect& aRect,
+                                  const WrRect& aClip,
+                                  const WrRect& aBoxBounds,
+                                  const WrPoint& aOffset,
+                                  const WrColor& aColor,
+                                  const float& aBlurRadius,
+                                  const float& aSpreadRadius,
+                                  const float& aBorderRadius,
+                                  const WrBoxShadowClipMode& aClipMode)
+{
+  wr_dp_push_box_shadow(mWrState, aRect, aClip,
+                        aBoxBounds, aOffset, aColor,
+                        aBlurRadius, aSpreadRadius, aBorderRadius,
+                        aClipMode);
+}
+
 } // namespace wr
 } // namespace mozilla
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -142,16 +142,26 @@ public:
 
   void PushText(const WrRect& aBounds,
                 const WrRect& aClip,
                 const gfx::Color& aColor,
                 wr::FontKey aFontKey,
                 Range<const WrGlyphInstance> aGlyphBuffer,
                 float aGlyphSize);
 
+  void PushBoxShadow(const WrRect& aRect,
+                     const WrRect& aClip,
+                     const WrRect& aBoxBounds,
+                     const WrPoint& aOffset,
+                     const WrColor& aColor,
+                     const float& aBlurRadius,
+                     const float& aSpreadRadius,
+                     const float& aBorderRadius,
+                     const WrBoxShadowClipMode& aClipMode);
+
   // Try to avoid using this when possible.
   WrState* Raw() { return mWrState; }
 protected:
   WrState* mWrState;
 
   friend class WebRenderAPI;
 };
 
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -5,21 +5,22 @@ use std::os::raw::{c_void, c_char};
 use gleam::gl;
 use webrender_traits::{BorderSide, BorderStyle, BorderRadius};
 use webrender_traits::{PipelineId, ClipRegion, PropertyBinding};
 use webrender_traits::{Epoch, ColorF, GlyphInstance, ImageDescriptor};
 use webrender_traits::{FilterOp, ImageData, ImageFormat, ImageKey, ImageMask, ImageRendering, RendererKind, MixBlendMode};
 use webrender_traits::{ExternalImageId, RenderApi, FontKey};
 use webrender_traits::{DeviceUintSize, ExternalEvent};
 use webrender_traits::{LayoutPoint, LayoutRect, LayoutSize, LayoutTransform};
-use webrender_traits::ServoScrollRootId;
+use webrender_traits::{BoxShadowClipMode, LayerPixel, ServoScrollRootId};
 use webrender::renderer::{Renderer, RendererOptions};
 use webrender::renderer::{ExternalImage, ExternalImageHandler, ExternalImageSource};
 use webrender::{ApiRecordingReceiver, BinaryRecorder};
 use app_units::Au;
+use euclid::TypedPoint2D;
 
 extern crate webrender_traits;
 
 static ENABLE_RECORDING: bool = false;
 
 // This macro adds some checks to make sure we notice when the memory representation of
 // types change.
 macro_rules! check_ffi_type {
@@ -444,16 +445,37 @@ impl ExternalImageHandler for WrExternal
     }
 
     fn release(&mut self, id: ExternalImageId) {
         (self.release_func)(self.external_image_obj, id);
     }
 }
 
 #[repr(C)]
+pub enum WrBoxShadowClipMode
+{
+    None,
+    Outset,
+    Inset,
+}
+
+impl WrBoxShadowClipMode
+{
+   pub fn to_box_shadow_clip_mode(self) -> BoxShadowClipMode
+   {
+       match self
+       {
+           WrBoxShadowClipMode::None => BoxShadowClipMode::None,
+           WrBoxShadowClipMode::Outset => BoxShadowClipMode::Outset,
+           WrBoxShadowClipMode::Inset => BoxShadowClipMode::Inset,
+       }
+   }
+}
+
+#[repr(C)]
 pub enum WrMixBlendMode
 {
     Normal,
     Multiply,
     Screen,
     Overlay,
     Darken,
     Lighten,
@@ -621,16 +643,34 @@ pub extern fn wr_dp_push_rect(state: &mu
 
     state.frame_builder.dl_builder.push_rect(
                                     rect.to_rect(),
                                     clip_region,
                                     color.to_color());
 }
 
 #[no_mangle]
+pub extern fn wr_dp_push_box_shadow(state: &mut WrState, rect: WrRect, clip: WrRect,
+                                    box_bounds: WrRect, offset: WrPoint, color: WrColor,
+                                    blur_radius: f32, spread_radius: f32, border_radius: f32,
+                                    clip_mode: WrBoxShadowClipMode) {
+    assert!( unsafe { is_in_compositor_thread() });
+    let clip_region = state.frame_builder.dl_builder.new_clip_region(&clip.to_rect(), Vec::new(), None);
+    state.frame_builder.dl_builder.push_box_shadow(rect.to_rect(),
+                                                   clip_region,
+                                                   box_bounds.to_rect(),
+                                                   offset.to_point(),
+                                                   color.to_color(),
+                                                   blur_radius,
+                                                   spread_radius,
+                                                   border_radius,
+                                                   clip_mode.to_box_shadow_clip_mode());
+}
+
+#[no_mangle]
 pub extern fn wr_dp_push_border(state: &mut WrState, rect: WrRect, clip: WrRect,
                                 top: WrBorderSide, right: WrBorderSide, bottom: WrBorderSide, left: WrBorderSide,
                                 radius: WrBorderRadius) {
     assert!( unsafe { is_in_compositor_thread() });
     let clip_region = state.frame_builder.dl_builder.new_clip_region(&clip.to_rect(), Vec::new(), None);
     state.frame_builder.dl_builder.push_border(
                                     rect.to_rect(),
                                     clip_region,
@@ -716,16 +756,17 @@ impl WrLayoutSize
 {
     pub fn to_layout_size(&self) -> LayoutSize
     {
         LayoutSize::new(self.width, self.height)
     }
 }
 
 #[repr(C)]
+#[derive(Debug)]
 pub struct WrRect
 {
     x: f32,
     y: f32,
     width: f32,
     height: f32
 }
 
@@ -733,16 +774,31 @@ impl WrRect
 {
     pub fn to_rect(&self) -> LayoutRect
     {
         LayoutRect::new(LayoutPoint::new(self.x, self.y), LayoutSize::new(self.width, self.height))
     }
 }
 
 #[repr(C)]
+pub struct WrPoint
+{
+    x: f32,
+    y: f32
+}
+
+impl WrPoint
+{
+    pub fn to_point(&self) -> TypedPoint2D<f32, LayerPixel>
+    {
+        TypedPoint2D::new(self.x, self.y)
+    }
+}
+
+#[repr(C)]
 pub struct WrImageMask
 {
     image: ImageKey,
     rect: WrRect,
     repeat: bool
 }
 
 impl WrImageMask
--- a/gfx/webrender_bindings/webrender_ffi.h
+++ b/gfx/webrender_bindings/webrender_ffi.h
@@ -64,16 +64,23 @@ WR_DECL_FFI_2(WrFontKey, uint32_t, uint3
 
 bool is_in_compositor_thread();
 bool is_in_render_thread();
 void* get_proc_address_from_glcontext(void* glcontext_ptr, const char* procname);
 
 // -----
 // Enums used in C++ code with corresponding enums in Rust code
 // -----
+enum class WrBoxShadowClipMode {
+  None,
+  Outset,
+  Inset,
+
+  Sentinel /* this must be last, for IPC serialization purposes */
+};
 
 enum class WrImageFormat: uint32_t
 {
   Invalid = 0,
   A8      = 1,
   RGB8    = 2,
   RGBA8   = 3,
   RGBAF32 = 4,
@@ -244,16 +251,27 @@ struct WrRect
 
   bool operator==(const WrRect& aRhs) const
   {
     return x == aRhs.x && y == aRhs.y &&
            width == aRhs.width && height == aRhs.height;
   }
 };
 
+struct WrPoint
+{
+  float x;
+  float y;
+
+  bool operator==(const WrPoint& aRhs) const {
+    return x == aRhs.x && y == aRhs.y;
+  }
+
+};
+
 struct WrImageMask
 {
   WrImageKey image;
   WrRect rect;
   bool repeat;
 
   bool operator==(const WrImageMask& aRhs) const
   {
@@ -482,13 +500,20 @@ WR_FUNC;
 
 // It is the responsibility of the caller to manage the dst_buffer memory
 // and also free it at the proper time.
 WR_INLINE const uint8_t*
 wr_renderer_readback(uint32_t width, uint32_t height,
                      uint8_t* dst_buffer, size_t buffer_length)
 WR_FUNC;
 
+WR_INLINE void
+wr_dp_push_box_shadow(WrState* wrState, WrRect rect, WrRect clip,
+                      WrRect box_bounds, WrPoint offset, WrColor color,
+                      float blur_radius, float spread_radius, float border_radius,
+                      WrBoxShadowClipMode clip_mode)
+WR_FUNC;
+
 #undef WR_FUNC
 #undef WR_DESTRUCTOR_SAFE_FUNC
 } // extern "C"
 
 #endif // WR_h
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -77,16 +77,17 @@
 #include "nsCaret.h"
 #include "nsISelection.h"
 #include "nsDOMTokenList.h"
 #include "mozilla/RuleNodeCacheConditions.h"
 #include "nsCSSProps.h"
 #include "nsPluginFrame.h"
 #include "nsSVGMaskFrame.h"
 #include "mozilla/layers/WebRenderLayerManager.h"
+#include "mozilla/layers/WebRenderDisplayItemLayer.h"
 #include "mozilla/layers/WebRenderMessages.h"
 
 // GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
 // GetTickCount().
 #ifdef GetCurrentTime
 #undef GetCurrentTime
 #endif
 
@@ -4341,17 +4342,17 @@ nsDisplayCaret::Paint(nsDisplayListBuild
                       nsRenderingContext* aCtx) {
   // Note: Because we exist, we know that the caret is visible, so we don't
   // need to check for the caret's visibility.
   mCaret->PaintCaret(*aCtx->GetDrawTarget(), mFrame, ToReferenceFrame());
 }
 
 void
 nsDisplayCaret::CreateWebRenderCommands(nsTArray<WebRenderCommand>& aCommands,
-                                        WebRenderLayer* aLayer) {
+                                        WebRenderDisplayItemLayer* aLayer) {
   using namespace mozilla::layers;
   int32_t contentOffset;
   nsIFrame* frame = mCaret->GetFrame(&contentOffset);
   if (!frame) {
     return;
   }
   NS_ASSERTION(frame == mFrame, "We're referring different frame");
 
@@ -4726,16 +4727,97 @@ nsDisplayBoxShadowOuter::ComputeVisibili
     return false;
   }
 
   // Store the actual visible region
   mVisibleRegion.And(*aVisibleRegion, mVisibleRect);
   return true;
 }
 
+
+LayerState
+nsDisplayBoxShadowOuter::GetLayerState(nsDisplayListBuilder* aBuilder,
+                                                  LayerManager* aManager,
+                                                  const ContainerLayerParameters& aParameters)
+{
+  if (gfxPrefs::LayersAllowOuterBoxShadow()) {
+    return LAYER_ACTIVE;
+  }
+
+  return LAYER_NONE;
+}
+
+already_AddRefed<Layer>
+nsDisplayBoxShadowOuter::BuildLayer(nsDisplayListBuilder* aBuilder,
+                                    LayerManager* aManager,
+                                    const ContainerLayerParameters& aContainerParameters)
+{
+  return BuildDisplayItemLayer(aBuilder, aManager, aContainerParameters);
+}
+
+void
+nsDisplayBoxShadowOuter::CreateWebRenderCommands(nsTArray<WebRenderCommand>& aCommands,
+                                                 WebRenderDisplayItemLayer* aLayer)
+{
+  int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
+  nsPoint offset = ToReferenceFrame();
+  nsRect borderRect = mFrame->VisualBorderRectRelativeToSelf() + offset;
+  //nsPresContext* presContext = mFrame->PresContext();
+  AutoTArray<nsRect,10> rects;
+  nsRegion visible = aLayer->GetVisibleRegion().ToAppUnits(appUnitsPerDevPixel);
+
+  ComputeDisjointRectangles(visible, &rects);
+
+  nsCSSShadowArray* shadows = mFrame->StyleEffects()->mBoxShadow;
+  if (!shadows)
+    return;
+
+  // Everything here is in app units, change to device units.
+  for (uint32_t i = 0; i < rects.Length(); ++i) {
+    Rect clipRect = NSRectToRect(rects[i], appUnitsPerDevPixel);
+    Rect gfxBorderRect = NSRectToRect(borderRect, appUnitsPerDevPixel);
+
+    Rect deviceClipRect = aLayer->RelativeToParent(clipRect);
+    Rect deviceBoxRect = aLayer->RelativeToParent(gfxBorderRect);
+
+    for (uint32_t j = shadows->Length(); j > 0; --j) {
+      nsCSSShadowItem* shadowItem = shadows->ShadowAt(j - 1);
+      nscoord blurRadius = shadowItem->mRadius;
+      float gfxBlurRadius = blurRadius / appUnitsPerDevPixel;
+
+      // TODO: Have to refactor our nsCSSRendering
+      // to get the acual rects correct.
+      nscolor shadowColor;
+      if (shadowItem->mHasColor)
+        shadowColor = shadowItem->mColor;
+      else
+        shadowColor = mFrame->StyleColor()->mColor;
+
+      Color gfxShadowColor(Color::FromABGR(shadowColor));
+      gfxShadowColor.a *= mOpacity;
+
+      WrPoint offset;
+      offset.x = shadowItem->mXOffset;
+      offset.y = shadowItem->mYOffset;
+
+      aCommands.AppendElement(OpDPPushBoxShadow(
+                              wr::ToWrRect(deviceBoxRect),
+                              wr::ToWrRect(deviceClipRect),
+                              wr::ToWrRect(deviceBoxRect),
+                              offset,
+                              wr::ToWrColor(gfxShadowColor),
+                              gfxBlurRadius,
+                              0,
+                              0,
+                              WrBoxShadowClipMode::Outset
+      ));
+    }
+  }
+}
+
 void
 nsDisplayBoxShadowOuter::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                                    const nsDisplayItemGeometry* aGeometry,
                                                    nsRegion* aInvalidRegion)
 {
   const nsDisplayBoxShadowOuterGeometry* geometry =
     static_cast<const nsDisplayBoxShadowOuterGeometry*>(aGeometry);
   bool snap;
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -53,17 +53,17 @@ class nsCaret;
 
 namespace mozilla {
 class FrameLayerBuilder;
 namespace layers {
 class Layer;
 class ImageLayer;
 class ImageContainer;
 class WebRenderCommand;
-class WebRenderLayer;
+class WebRenderDisplayItemLayer;
 } // namespace layers
 } // namespace mozilla
 
 // A set of blend modes, that never includes OP_OVER (since it's
 // considered the default, rather than a specific blend mode).
 typedef mozilla::EnumSet<mozilla::gfx::CompositionOp> BlendModeSet;
 
 /*
@@ -1582,17 +1582,17 @@ public:
   typedef mozilla::DisplayItemClipChain DisplayItemClipChain;
   typedef mozilla::ActiveScrolledRoot ActiveScrolledRoot;
   typedef mozilla::layers::FrameMetrics FrameMetrics;
   typedef mozilla::layers::ScrollMetadata ScrollMetadata;
   typedef mozilla::layers::FrameMetrics::ViewID ViewID;
   typedef mozilla::layers::Layer Layer;
   typedef mozilla::layers::LayerManager LayerManager;
   typedef mozilla::layers::WebRenderCommand WebRenderCommand;
-  typedef mozilla::layers::WebRenderLayer WebRenderLayer;
+  typedef mozilla::layers::WebRenderDisplayItemLayer WebRenderDisplayItemLayer;
   typedef mozilla::LayerState LayerState;
   typedef class mozilla::gfx::DrawTarget DrawTarget;
 
   // This is never instantiated directly (it has pure virtual methods), so no
   // need to count constructors and destructors.
   nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame);
   nsDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                 const ActiveScrolledRoot* aActiveScrolledRoot);
@@ -1923,17 +1923,17 @@ public:
   { return nullptr; }
 
   /**
     * Create the WebRenderCommands required to paint this display item.
     * The layer this item is in is passed in as rects must be relative
     * to their parent.
     */
    virtual void CreateWebRenderCommands(nsTArray<WebRenderCommand>& aCommands,
-                                        WebRenderLayer* aLayer) {}
+                                        WebRenderDisplayItemLayer* aLayer) {}
   /**
    * Builds a DisplayItemLayer and sets the display item to this.
    */
    already_AddRefed<Layer>
    BuildDisplayItemLayer(nsDisplayListBuilder* aBuilder,
                          LayerManager* aManager,
                          const ContainerLayerParameters& aContainerParameters);
 
@@ -2819,17 +2819,17 @@ public:
 
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) override;
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) override;
   virtual void CreateWebRenderCommands(nsTArray<WebRenderCommand>& aCommands,
-                                        WebRenderLayer* aLayer) override;
+                                        WebRenderDisplayItemLayer* aLayer) override;
 
 protected:
   RefPtr<nsCaret> mCaret;
   nsRect mBounds;
 };
 
 /**
  * The standard display item to paint the CSS borders of a frame.
@@ -3374,16 +3374,25 @@ public:
     return true;
   }
 
   virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override
   {
     return new nsDisplayBoxShadowOuterGeometry(this, aBuilder, mOpacity);
   }
 
+  virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
+                                   LayerManager* aManager,
+                                   const ContainerLayerParameters& aParameters) override;
+  virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
+                                             LayerManager* aManager,
+                                             const ContainerLayerParameters& aContainerParameters) override;
+  virtual void CreateWebRenderCommands(nsTArray<WebRenderCommand>& aCommands,
+                                       WebRenderDisplayItemLayer* aLayer) override;
+
   nsRect GetBoundsInternal();
 
 private:
   nsRegion mVisibleRegion;
   nsRect mBounds;
   float mOpacity;
 };