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 373009 687b3bd601ba93cf746f2ef1cd3af2c60f7d2128
parent 373008 9a03f0308986482929af1f6cf62c0edcd957ea73
child 373010 ae5c9d27cc3cb7e309b9b21d12a4c338a5de82a0
push id10863
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 23:02:23 +0000
treeherdermozilla-aurora@0931190cd725 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjmuizelaar
bugs1339661
milestone54.0a1
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;
 };