Bug 1343979 - Add webrender support for ButtonBorderBackground. r=ethlin
authorMason Chang <mchang@mozilla.com>
Wed, 08 Mar 2017 08:31:46 -0800
changeset 347318 683fbabdfd8fb943884148259e747811de727d78
parent 347317 1ff6805a848268bd2ab84c27b59fa35f93f07bef
child 347321 0820edb5e1f536caf723bb2fb1ac70aced81faae
push id88014
push userkwierso@gmail.com
push dateMon, 13 Mar 2017 23:39:54 +0000
treeherdermozilla-inbound@474dc1155078 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersethlin
bugs1343979
milestone55.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 1343979 - Add webrender support for ButtonBorderBackground. r=ethlin
gfx/layers/moz.build
gfx/layers/wr/WebRenderBorderLayer.cpp
gfx/layers/wr/WebRenderBorderLayer.h
gfx/thebes/gfxPrefs.h
layout/forms/moz.build
layout/forms/nsButtonFrameRenderer.cpp
layout/forms/nsButtonFrameRenderer.h
layout/painting/nsCSSRenderingBorders.h
layout/painting/nsDisplayList.cpp
layout/painting/nsDisplayList.h
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -202,16 +202,17 @@ EXPORTS.mozilla.layers += [
     'opengl/TextureClientOGL.h',
     'opengl/TextureHostOGL.h',
     'PersistentBufferProvider.h',
     'RenderTrace.h',
     'SourceSurfaceSharedData.h',
     'SourceSurfaceVolatileData.h',
     'TextureWrapperImage.h',
     'TransactionIdAllocator.h',
+    'wr/WebRenderBorderLayer.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',
--- a/gfx/layers/wr/WebRenderBorderLayer.cpp
+++ b/gfx/layers/wr/WebRenderBorderLayer.cpp
@@ -12,16 +12,46 @@
 #include "mozilla/layers/WebRenderBridgeChild.h"
 #include "mozilla/webrender/WebRenderTypes.h"
 
 namespace mozilla {
 namespace layers {
 
 using namespace mozilla::gfx;
 
+/* static */void
+WebRenderBorderLayer::CreateWebRenderCommands(wr::DisplayListBuilder& aBuilder,
+                                              WebRenderLayer* aLayer,
+                                              BorderColors& aColors,
+                                              BorderCorners& aCorners,
+                                              BorderWidths& aWidths,
+                                              BorderStyles& aBorderStyles,
+                                              Rect aRect,
+                                              Rect aClipRect,
+                                              Rect aRelBounds,
+                                              Rect aOverflow)
+{
+  aBuilder.PushStackingContext(wr::ToWrRect(aRelBounds),
+                               wr::ToWrRect(aOverflow),
+                               nullptr,
+                               1.0f,
+                               aLayer->GetLayer()->GetTransform(),
+                               WrMixBlendMode::Normal);
+
+  aBuilder.PushBorder(wr::ToWrRect(aRect), wr::ToWrRect(aClipRect),
+                      wr::ToWrBorderSide(aWidths[0], aColors[0], aBorderStyles[0]),
+                      wr::ToWrBorderSide(aWidths[1], aColors[1], aBorderStyles[1]),
+                      wr::ToWrBorderSide(aWidths[2], aColors[2], aBorderStyles[2]),
+                      wr::ToWrBorderSide(aWidths[3], aColors[3], aBorderStyles[3]),
+                      wr::ToWrBorderRadius(aCorners[0], aCorners[1],
+                                           aCorners[3], aCorners[2]));
+
+  aBuilder.PopStackingContext();
+}
+
 void
 WebRenderBorderLayer::RenderLayer(wr::DisplayListBuilder& aBuilder)
 {
   WrScrollFrameStackingContextGenerator scrollFrames(this);
 
   LayerIntRect bounds = GetVisibleRegion().GetBounds();
   Rect rect(0, 0, bounds.width, bounds.height);
   Rect clip;
--- a/gfx/layers/wr/WebRenderBorderLayer.h
+++ b/gfx/layers/wr/WebRenderBorderLayer.h
@@ -16,16 +16,28 @@ class WebRenderBorderLayer : public WebR
                              public BorderLayer {
 public:
   explicit WebRenderBorderLayer(WebRenderLayerManager* aLayerManager)
     : BorderLayer(aLayerManager, static_cast<WebRenderLayer*>(this))
   {
     MOZ_COUNT_CTOR(WebRenderBorderLayer);
   }
 
+  static void
+  CreateWebRenderCommands(wr::DisplayListBuilder& aBuilder,
+                          WebRenderLayer* aLayer,
+                          BorderColors& aColors,
+                          BorderCorners& aCorners,
+                          BorderWidths& aWidths,
+                          BorderStyles& aBorderStyles,
+                          gfx::Rect aRect,
+                          gfx::Rect aClipRect,
+                          gfx::Rect aRelBounds,
+                          gfx::Rect aOverflow);
+
 protected:
   virtual ~WebRenderBorderLayer()
   {
     MOZ_COUNT_DTOR(WebRenderBorderLayer);
   }
 
 public:
   Layer* GetLayer() override { return this; }
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -460,17 +460,18 @@ private:
   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(Live, "layers.advanced.boxshadow-inset-layers", LayersAllowInsetBoxShadow, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.outline-layers",        LayersAllowOutlineLayers, bool, false);
-  DECL_GFX_PREF(Skip, "layers.allow-d3d9-fallback",            LayersAllowD3D9Fallback, bool, false);
+  DECL_GFX_PREF(Live, "layers.advanced.displaybuttonborder-layers", LayersAllowDisplayButtonBorder, 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
   // If MOZ_GFX_OPTIMIZE_MOBILE is defined, we force component alpha off
--- a/layout/forms/moz.build
+++ b/layout/forms/moz.build
@@ -38,16 +38,18 @@ UNIFIED_SOURCES += [
     'nsProgressFrame.cpp',
     'nsRangeFrame.cpp',
     'nsSelectsAreaFrame.cpp',
     'nsTextControlFrame.cpp',
 ]
 
 FINAL_LIBRARY = 'xul'
 
+include('/ipc/chromium/chromium-config.mozbuild')
+
 LOCAL_INCLUDES += [
     '../../editor/txmgr',
     '../base',
     '../generic',
     '../painting',
     '../style',
     '../xul',
     '/dom/base',
--- a/layout/forms/nsButtonFrameRenderer.cpp
+++ b/layout/forms/nsButtonFrameRenderer.cpp
@@ -10,23 +10,29 @@
 #include "nsNameSpaceManager.h"
 #include "mozilla/StyleSetHandle.h"
 #include "mozilla/StyleSetHandleInlines.h"
 #include "nsDisplayList.h"
 #include "nsITheme.h"
 #include "nsFrame.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/dom/Element.h"
+#include "Layers.h"
+#include "gfxPrefs.h"
+#include "gfxUtils.h"
+#include "mozilla/layers/WebRenderDisplayItemLayer.h"
+#include "mozilla/layers/WebRenderBorderLayer.h"
 
 #define ACTIVE   "active"
 #define HOVER    "hover"
 #define FOCUS    "focus"
 
 using namespace mozilla;
 using namespace mozilla::image;
+using namespace mozilla::layers;
 
 nsButtonFrameRenderer::nsButtonFrameRenderer()
 {
   MOZ_COUNT_CTOR(nsButtonFrameRenderer);
 }
 
 nsButtonFrameRenderer::~nsButtonFrameRenderer()
 {
@@ -68,50 +74,45 @@ nsButtonFrameRenderer::isDisabled()
   return mFrame->GetContent()->AsElement()->
     State().HasState(NS_EVENT_STATE_DISABLED);
 }
 
 class nsDisplayButtonBoxShadowOuter : public nsDisplayItem {
 public:
   nsDisplayButtonBoxShadowOuter(nsDisplayListBuilder* aBuilder,
                                 nsButtonFrameRenderer* aRenderer)
-    : nsDisplayItem(aBuilder, aRenderer->GetFrame()), mBFR(aRenderer) {
+    : nsDisplayItem(aBuilder, aRenderer->GetFrame()) {
     MOZ_COUNT_CTOR(nsDisplayButtonBoxShadowOuter);
   }
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayButtonBoxShadowOuter() {
     MOZ_COUNT_DTOR(nsDisplayButtonBoxShadowOuter);
   }
 #endif  
   
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx) override;
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
                            bool* aSnap) override;
   NS_DISPLAY_DECL_NAME("ButtonBoxShadowOuter", TYPE_BUTTON_BOX_SHADOW_OUTER)
-private:
-  nsButtonFrameRenderer* mBFR;
 };
 
 nsRect
 nsDisplayButtonBoxShadowOuter::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
   *aSnap = false;
   return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
 }
 
 void
 nsDisplayButtonBoxShadowOuter::Paint(nsDisplayListBuilder* aBuilder,
                                      nsRenderingContext* aCtx) {
   nsRect frameRect = nsRect(ToReferenceFrame(), mFrame->GetSize());
 
-  nsRect buttonRect;
-  mBFR->GetButtonRect(frameRect, buttonRect);
-
   nsCSSRendering::PaintBoxShadowOuter(mFrame->PresContext(), *aCtx, mFrame,
-                                      buttonRect, mVisibleRect);
+                                      frameRect, mVisibleRect);
 }
 
 class nsDisplayButtonBorder : public nsDisplayItem {
 public:
   nsDisplayButtonBorder(nsDisplayListBuilder* aBuilder,
                                   nsButtonFrameRenderer* aRenderer)
     : nsDisplayItem(aBuilder, aRenderer->GetFrame()), mBFR(aRenderer) {
     MOZ_COUNT_CTOR(nsDisplayButtonBorder);
@@ -129,27 +130,131 @@ public:
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx) override;
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
                            bool* aSnap) override;
   virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override;
   virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                          const nsDisplayItemGeometry* aGeometry,
                                          nsRegion *aInvalidRegion) override;
+  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(mozilla::wr::DisplayListBuilder& aBuilder,
+                                       nsTArray<WebRenderParentCommand>& aParentCommands,
+                                       WebRenderDisplayItemLayer* aLayer) override;
   NS_DISPLAY_DECL_NAME("ButtonBorderBackground", TYPE_BUTTON_BORDER_BACKGROUND)
 private:
   nsButtonFrameRenderer* mBFR;
 };
 
 nsDisplayItemGeometry*
 nsDisplayButtonBorder::AllocateGeometry(nsDisplayListBuilder* aBuilder)
 {
   return new nsDisplayItemGenericImageGeometry(this, aBuilder);
 }
 
+LayerState
+nsDisplayButtonBorder::GetLayerState(nsDisplayListBuilder* aBuilder,
+                                     LayerManager* aManager,
+                                     const ContainerLayerParameters& aParameters)
+{
+  if (gfxPrefs::LayersAllowDisplayButtonBorder()) {
+    return LAYER_ACTIVE;
+  }
+
+  return LAYER_NONE;
+}
+
+already_AddRefed<Layer>
+nsDisplayButtonBorder::BuildLayer(nsDisplayListBuilder* aBuilder,
+                                  LayerManager* aManager,
+                                  const ContainerLayerParameters& aContainerParameters)
+{
+  return BuildDisplayItemLayer(aBuilder, aManager, aContainerParameters);
+}
+
+void
+nsDisplayButtonBorder::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
+                                               nsTArray<WebRenderParentCommand>& aCommands,
+                                               WebRenderDisplayItemLayer* aLayer)
+{
+  // This is really a combination of paint box shadow inner +
+  // paint border.
+  nsRect buttonRect = nsRect(ToReferenceFrame(), mFrame->GetSize());
+  nsRect dirtyRect = mVisibleRect;
+
+  // TODO: Figure out what to do with sync decode images
+  /*
+  PaintBorderFlags borderFlags = aBuilder->ShouldSyncDecodeImages()
+                               ? PaintBorderFlags::SYNC_DECODE_IMAGES
+                               : PaintBorderFlags();
+                               */
+
+  nsDisplayBoxShadowInner::CreateInsetBoxShadowWebRenderCommands(aBuilder,
+                                                                 aLayer,
+                                                                 mFrame,
+                                                                 buttonRect);
+
+  nsPoint offset = ToReferenceFrame();
+  Maybe<nsCSSBorderRenderer> br =
+    nsCSSRendering::CreateBorderRenderer(mFrame->PresContext(),
+                                         nullptr,
+                                         mFrame,
+                                         nsRect(),
+                                         nsRect(offset, mFrame->GetSize()),
+                                         mFrame->StyleContext(),
+                                         mFrame->GetSkipSides());
+
+  if (!br) {
+    NS_WARNING("Could not create border renderer during nsDisplayButtonBorder");
+    return;
+  }
+
+  BorderColors colors;
+  BorderCorners corners;
+  BorderWidths widths;
+  BorderStyles borderStyles;
+
+  NS_FOR_CSS_SIDES(i) {
+    colors[i] = gfx::ToDeviceColor(br->mBorderColors[i]);
+    widths[i] = br->mBorderWidths[i];
+    borderStyles[i] = br->mBorderStyles[i];
+  }
+  NS_FOR_CSS_FULL_CORNERS(corner) {
+      corners[corner] = LayerSize(br->mBorderRadii[corner].width,
+                                  br->mBorderRadii[corner].height);
+  }
+
+  gfx::Rect relBounds = aLayer->VisibleBoundsRelativeToParent();
+  gfx::Rect overflow(0, 0, relBounds.width, relBounds.height);
+
+  int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
+  gfx::Rect gfxDirtyRect = aLayer->RelativeToParent(NSRectToRect(dirtyRect, appUnitsPerDevPixel));
+
+  // The bounds rect starts from 0 here because the stacking context
+  // is created with the proper relative bounds.
+  LayerIntRect bounds = aLayer->GetVisibleRegion().GetBounds();
+  gfx::Rect boundsRect(0, 0, bounds.width, bounds.height);
+
+  WebRenderBorderLayer::CreateWebRenderCommands(aBuilder,
+                                                aLayer,
+                                                colors,
+                                                corners,
+                                                widths,
+                                                borderStyles,
+                                                boundsRect,
+                                                gfxDirtyRect,
+                                                relBounds,
+                                                overflow);
+}
+
 void
 nsDisplayButtonBorder::ComputeInvalidationRegion(
   nsDisplayListBuilder* aBuilder,
   const nsDisplayItemGeometry* aGeometry,
   nsRegion *aInvalidRegion)
 {
   auto geometry =
     static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
@@ -158,18 +263,19 @@ nsDisplayButtonBorder::ComputeInvalidati
       geometry->ShouldInvalidateToSyncDecodeImages()) {
     bool snap;
     aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
   }
 
   nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
 }
 
-void nsDisplayButtonBorder::Paint(nsDisplayListBuilder* aBuilder,
-                                  nsRenderingContext* aCtx)
+void
+nsDisplayButtonBorder::Paint(nsDisplayListBuilder* aBuilder,
+                             nsRenderingContext* aCtx)
 {
   NS_ASSERTION(mFrame, "No frame?");
   nsPresContext* pc = mFrame->PresContext();
   nsRect r = nsRect(ToReferenceFrame(), mFrame->GetSize());
 
   // draw the border and background inside the focus and outline borders
   DrawResult result =
     mBFR->PaintBorder(aBuilder, pc, *aCtx, mVisibleRect, r);
@@ -254,18 +360,17 @@ nsButtonFrameRenderer::DisplayButton(nsD
                                      nsDisplayList* aBackground,
                                      nsDisplayList* aForeground)
 {
   if (mFrame->StyleEffects()->mBoxShadow) {
     aBackground->AppendNewToTop(new (aBuilder)
       nsDisplayButtonBoxShadowOuter(aBuilder, this));
   }
 
-  nsRect buttonRect;
-  GetButtonRect(mFrame->GetRectRelativeToSelf(), buttonRect);
+  nsRect buttonRect = mFrame->GetRectRelativeToSelf();
 
   nsDisplayBackgroundImage::AppendBackgroundItemsToTop(
     aBuilder, mFrame, buttonRect, aBackground);
 
   aBackground->AppendNewToTop(new (aBuilder)
     nsDisplayButtonBorder(aBuilder, this));
 
   // Only display focus rings if we actually have them. Since at most one
@@ -275,17 +380,17 @@ nsButtonFrameRenderer::DisplayButton(nsD
       nsDisplayButtonForeground(aBuilder, this));
   }
   return NS_OK;
 }
 
 void
 nsButtonFrameRenderer::GetButtonInnerFocusRect(const nsRect& aRect, nsRect& aResult)
 {
-  GetButtonRect(aRect, aResult);
+  aResult = aRect;
   aResult.Deflate(mFrame->GetUsedBorderAndPadding());
 
   nsMargin innerFocusPadding(0,0,0,0);
   if (mInnerFocusStyle) {
     mInnerFocusStyle->StylePadding()->GetPadding(innerFocusPadding);
   }
   aResult.Inflate(innerFocusPadding);
 }
@@ -324,43 +429,33 @@ DrawResult
 nsButtonFrameRenderer::PaintBorder(
   nsDisplayListBuilder* aBuilder,
   nsPresContext* aPresContext,
   nsRenderingContext& aRenderingContext,
   const nsRect& aDirtyRect,
   const nsRect& aRect)
 {
   // get the button rect this is inside the focus and outline rects
-  nsRect buttonRect;
-  GetButtonRect(aRect, buttonRect);
-
+  nsRect buttonRect = aRect;
   nsStyleContext* context = mFrame->StyleContext();
 
   PaintBorderFlags borderFlags = aBuilder->ShouldSyncDecodeImages()
                                ? PaintBorderFlags::SYNC_DECODE_IMAGES
                                : PaintBorderFlags();
 
   nsCSSRendering::PaintBoxShadowInner(aPresContext, aRenderingContext,
                                       mFrame, buttonRect);
 
   DrawResult result =
     nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, mFrame,
                                 aDirtyRect, buttonRect, context, borderFlags);
 
   return result;
 }
 
-
-void
-nsButtonFrameRenderer::GetButtonRect(const nsRect& aRect, nsRect& r)
-{
-  r = aRect;
-}
-
-
 /**
  * Call this when styles change
  */
 void
 nsButtonFrameRenderer::ReResolveStyles(nsPresContext* aPresContext)
 {
   // get all the styles
   nsStyleContext* context = mFrame->StyleContext();
--- a/layout/forms/nsButtonFrameRenderer.h
+++ b/layout/forms/nsButtonFrameRenderer.h
@@ -51,17 +51,16 @@ public:
 
   void SetFrame(nsFrame* aFrame, nsPresContext* aPresContext);
  
   void SetDisabled(bool aDisabled, bool notify);
 
   bool isActive();
   bool isDisabled();
 
-  void GetButtonRect(const nsRect& aRect, nsRect& aResult);
   void GetButtonInnerFocusRect(const nsRect& aRect, nsRect& aResult);
 
   nsStyleContext* GetStyleContext(int32_t aIndex) const;
   void SetStyleContext(int32_t aIndex, nsStyleContext* aStyleContext);
   void ReResolveStyles(nsPresContext* aPresContext);
 
   nsIFrame* GetFrame();
 
--- a/layout/painting/nsCSSRenderingBorders.h
+++ b/layout/painting/nsCSSRenderingBorders.h
@@ -74,16 +74,17 @@ class nsCSSBorderRenderer final
   typedef mozilla::gfx::Path Path;
   typedef mozilla::gfx::Point Point;
   typedef mozilla::gfx::Rect Rect;
   typedef mozilla::gfx::RectCornerRadii RectCornerRadii;
   typedef mozilla::gfx::StrokeOptions StrokeOptions;
 
   friend class nsDisplayBorder;
   friend class nsDisplayOutline;
+  friend class nsDisplayButtonBorder;
 
 public:
 
   nsCSSBorderRenderer(nsPresContext* aPresContext,
                       const nsIDocument* aDocument,
                       DrawTarget* aDrawTarget,
                       const Rect& aDirtyRect,
                       Rect& aOuterRect,
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -4984,53 +4984,52 @@ nsDisplayBoxShadowInner::GetLayerState(n
 already_AddRefed<Layer>
 nsDisplayBoxShadowInner::BuildLayer(nsDisplayListBuilder* aBuilder,
                                     LayerManager* aManager,
                                     const ContainerLayerParameters& aContainerParameters)
 {
   return BuildDisplayItemLayer(aBuilder, aManager, aContainerParameters);
 }
 
-void
-nsDisplayBoxShadowInner::CreateWebRenderCommands(wr::DisplayListBuilder& aBuilder,
-                                                 nsTArray<WebRenderParentCommand>& aParentCommands,
-                                                 WebRenderDisplayItemLayer* aLayer)
-{
-  if (!nsCSSRendering::CanPaintBoxShadowInner(mFrame)) {
+/* static */ void
+nsDisplayBoxShadowInner::CreateInsetBoxShadowWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
+                                                               WebRenderDisplayItemLayer* aLayer,
+                                                               nsIFrame* aFrame,
+                                                               const nsRect aBorderRect)
+{
+  if (!nsCSSRendering::CanPaintBoxShadowInner(aFrame)) {
     return;
   }
 
-  int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
-  nsPoint offset = ToReferenceFrame();
-  nsRect borderRect = nsRect(offset, mFrame->GetSize());
+  int32_t appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
 
   AutoTArray<nsRect,10> rects;
   nsRegion visible = aLayer->GetVisibleRegion().ToAppUnits(appUnitsPerDevPixel);
   ComputeDisjointRectangles(visible, &rects);
 
-  nsCSSShadowArray* shadows = mFrame->StyleEffects()->mBoxShadow;
+  nsCSSShadowArray* shadows = aFrame->StyleEffects()->mBoxShadow;
 
   for (uint32_t i = 0; i < rects.Length(); ++i) {
     Rect clipRect = NSRectToRect(rects[i], appUnitsPerDevPixel);
 
     for (uint32_t i = shadows->Length(); i > 0; --i) {
       nsCSSShadowItem* shadowItem = shadows->ShadowAt(i - 1);
       if (!shadowItem->mInset) {
         continue;
       }
 
       nsRect shadowRect =
-        nsCSSRendering::GetBoxShadowInnerPaddingRect(mFrame, borderRect);
+        nsCSSRendering::GetBoxShadowInnerPaddingRect(aFrame, aBorderRect);
       RectCornerRadii innerRadii;
-      nsCSSRendering::GetShadowInnerRadii(mFrame, borderRect, innerRadii);
+      nsCSSRendering::GetShadowInnerRadii(aFrame, aBorderRect, innerRadii);
 
       // Now translate everything to device pixels.
       Rect deviceBoxRect = NSRectToRect(shadowRect, appUnitsPerDevPixel);
       Rect deviceClipRect = aLayer->RelativeToParent(clipRect);
-      Color shadowColor = nsCSSRendering::GetShadowColor(shadowItem, mFrame, 1.0);
+      Color shadowColor = nsCSSRendering::GetShadowColor(shadowItem, aFrame, 1.0);
 
       Point shadowOffset;
       shadowOffset.x = (shadowItem->mXOffset / appUnitsPerDevPixel);
       shadowOffset.y = (shadowItem->mYOffset / appUnitsPerDevPixel);
 
       float blurRadius = float(shadowItem->mRadius) / float(appUnitsPerDevPixel);
       // TODO: WR doesn't support non-uniform border radii
       float borderRadius = innerRadii.TopLeft().width;
@@ -5040,19 +5039,31 @@ nsDisplayBoxShadowInner::CreateWebRender
       aBuilder.PushBoxShadow(wr::ToWrRect(deviceBoxRect),
                              wr::ToWrRect(deviceClipRect),
                              wr::ToWrRect(deviceBoxRect),
                              wr::ToWrPoint(shadowOffset),
                              wr::ToWrColor(shadowColor),
                              blurRadius,
                              spreadRadius,
                              borderRadius,
-                             WrBoxShadowClipMode::Inset);
-    }
-  }
+                             WrBoxShadowClipMode::Inset
+                             );
+    }
+  }
+}
+
+void
+nsDisplayBoxShadowInner::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
+                                                 nsTArray<WebRenderParentCommand>& aCommands,
+                                                 WebRenderDisplayItemLayer* aLayer)
+{
+  nsPoint offset = ToReferenceFrame();
+  nsRect borderRect = nsRect(offset, mFrame->GetSize());
+
+  nsDisplayBoxShadowInner::CreateInsetBoxShadowWebRenderCommands(aBuilder, aLayer, mFrame, borderRect);
 }
 
 bool
 nsDisplayBoxShadowInner::ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                            nsRegion* aVisibleRegion) {
   if (!nsDisplayItem::ComputeVisibility(aBuilder, aVisibleRegion)) {
     return false;
   }
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -3435,16 +3435,20 @@ public:
     if (!geometry->mPaddingRect.IsEqualInterior(GetPaddingRect())) {
       // nsDisplayBoxShadowInner is based around the padding rect, but it can
       // touch pixels outside of this. We should invalidate the entire bounds.
       bool snap;
       aInvalidRegion->Or(geometry->mBounds, GetBounds(aBuilder, &snap));
     }
   }
 
+  static void CreateInsetBoxShadowWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
+                                                    WebRenderDisplayItemLayer* aLayer,
+                                                    nsIFrame* aFrame,
+                                                    const nsRect aBorderRect);
   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(mozilla::wr::DisplayListBuilder& aBuilder,
                                        nsTArray<WebRenderParentCommand>& aParentCommand,