Bug 1407753 - Factor out webrender border code for reuse. r?jrmuizel draft
authorAlexis Beingessner <a.beingessner@gmail.com>
Fri, 13 Oct 2017 16:19:00 -0400
changeset 682726 0fe07ad344299da805c3e822ad46271f38e40b5e
parent 682254 a29052590fc6538b89641e690d11731ca8e78120
child 682727 13fd9a438ffba7f14033318d028227af07c0f6f7
push id85116
push userbmo:a.beingessner@gmail.com
push dateWed, 18 Oct 2017 17:07:29 +0000
reviewersjrmuizel
bugs1407753
milestone58.0a1
Bug 1407753 - Factor out webrender border code for reuse. r?jrmuizel Also explicitly disables the image-border and gradient-border cases, which were already accidentally disabled. They are too bitrotted to turn back on at the moment. MozReview-Commit-ID: FRXqemXQHJN
layout/painting/nsCSSRendering.cpp
layout/painting/nsCSSRendering.h
layout/painting/nsCSSRenderingBorders.cpp
layout/painting/nsCSSRenderingBorders.h
layout/painting/nsDisplayList.cpp
--- a/layout/painting/nsCSSRendering.cpp
+++ b/layout/painting/nsCSSRendering.cpp
@@ -688,16 +688,104 @@ nsCSSRendering::CreateBorderRenderer(nsP
     newStyleBorder.mBorderColor[side] = StyleComplexColor::FromColor(color);
   }
   return CreateBorderRendererWithStyleBorder(aPresContext, aDrawTarget,
                                              aForFrame, aDirtyRect, aBorderArea,
                                              newStyleBorder, aStyleContext,
                                              aSkipSides);
 }
 
+
+bool
+nsCSSRendering::CreateWebRenderCommandsForBorder(nsDisplayItem* aItem,
+                                                 nsIFrame* aForFrame,
+                                                 const nsRect& aBorderArea,
+                                                 mozilla::wr::DisplayListBuilder& aBuilder,
+                                                 mozilla::wr::IpcResourceUpdateQueue& aResources,
+                                                 const mozilla::layers::StackingContextHelper& aSc,
+                                                 mozilla::layers::WebRenderLayerManager* aManager,
+                                                 nsDisplayListBuilder* aDisplayListBuilder)
+{
+  // First try to draw a normal border
+  {
+    Maybe<nsCSSBorderRenderer> br =
+      nsCSSRendering::CreateBorderRenderer(aForFrame->PresContext(),
+                                           nullptr,
+                                           aForFrame,
+                                           nsRect(),
+                                           aBorderArea,
+                                           aForFrame->StyleContext(),
+                                           aForFrame->GetSkipSides());
+
+    if (br) {
+      if (!br->CanCreateWebRenderCommands()) {
+        return false;
+      }
+      br->CreateWebRenderCommands(aBuilder, aResources, aSc);
+      return true;
+    }
+  }
+
+  // Next try to draw an image border
+  const nsStyleBorder *styleBorder = aForFrame->StyleContext()->StyleBorder();
+  const nsStyleImage* image = &styleBorder->mBorderImageSource;
+
+  // Filter out unsupported image/border types
+  if (!image) {
+    return false;
+  }
+
+  // All this code bitrotted too much (but is almost right); disabled for now.
+  bool imageTypeSupported = false;
+  // FIXME(1409773): fix this: image->GetType() == eStyleImageType_Image
+  // FIXME(1409774): fix this: image->GetType() == eStyleImageType_Gradient;
+
+  if (!imageTypeSupported) {
+    return false;
+  }
+
+  if (styleBorder->mBorderImageRepeatH == NS_STYLE_BORDER_IMAGE_REPEAT_ROUND ||
+      styleBorder->mBorderImageRepeatH == NS_STYLE_BORDER_IMAGE_REPEAT_SPACE ||
+      styleBorder->mBorderImageRepeatV == NS_STYLE_BORDER_IMAGE_REPEAT_ROUND ||
+      styleBorder->mBorderImageRepeatV == NS_STYLE_BORDER_IMAGE_REPEAT_SPACE) {
+    return false;
+  }
+
+
+  uint32_t flags = 0;
+  if (aDisplayListBuilder->ShouldSyncDecodeImages()) {
+    flags |= nsImageRenderer::FLAG_SYNC_DECODE_IMAGES;
+  }
+
+  image::DrawResult result;
+  Maybe<nsCSSBorderImageRenderer> bir =
+    nsCSSBorderImageRenderer::CreateBorderImageRenderer(aForFrame->PresContext(),
+                                                        aForFrame,
+                                                        aBorderArea,
+                                                        *styleBorder,
+                                                        aItem->GetVisibleRect(),
+                                                        aForFrame->GetSkipSides(),
+                                                        flags,
+                                                        &result);
+
+  if (!bir) {
+    return false;
+  }
+
+  if (image->GetType() == eStyleImageType_Image &&
+      !bir->mImageRenderer.IsImageContainerAvailable(aManager, flags)) {
+    return false;
+  }
+
+  bir->CreateWebRenderCommands(aItem, aForFrame, aBuilder, aResources, aSc,
+                               aManager, aDisplayListBuilder);
+
+  return true;
+}
+
 nsCSSBorderRenderer
 ConstructBorderRenderer(nsPresContext* aPresContext,
                         nsStyleContext* aStyleContext,
                         DrawTarget* aDrawTarget,
                         nsIFrame* aForFrame,
                         const nsRect& aDirtyRect,
                         const nsRect& aBorderArea,
                         const nsStyleBorder& aStyleBorder,
--- a/layout/painting/nsCSSRendering.h
+++ b/layout/painting/nsCSSRendering.h
@@ -207,16 +207,26 @@ struct nsCSSRendering {
   static mozilla::Maybe<nsCSSBorderRenderer>
   CreateBorderRendererForOutline(nsPresContext* aPresContext,
                                  gfxContext* aRenderingContext,
                                  nsIFrame* aForFrame,
                                  const nsRect& aDirtyRect,
                                  const nsRect& aBorderArea,
                                  nsStyleContext* aStyleContext);
 
+
+  static bool CreateWebRenderCommandsForBorder(nsDisplayItem* aItem,
+                                               nsIFrame* aForFrame,
+                                               const nsRect& aBorderArea,
+                                               mozilla::wr::DisplayListBuilder& aBuilder,
+                                               mozilla::wr::IpcResourceUpdateQueue& aResources,
+                                               const mozilla::layers::StackingContextHelper& aSc,
+                                               mozilla::layers::WebRenderLayerManager* aManager,
+                                               nsDisplayListBuilder* aDisplayListBuilder);
+
   /**
    * Render the outline for an element using css rendering rules
    * for borders.
    */
   static void PaintOutline(nsPresContext* aPresContext,
                           gfxContext& aRenderingContext,
                           nsIFrame* aForFrame,
                           const nsRect& aDirtyRect,
--- a/layout/painting/nsCSSRenderingBorders.cpp
+++ b/layout/painting/nsCSSRenderingBorders.cpp
@@ -13,16 +13,17 @@
 #include "mozilla/gfx/PathHelpers.h"
 #include "BorderConsts.h"
 #include "DashedCornerFinder.h"
 #include "DottedCornerFinder.h"
 #include "nsLayoutUtils.h"
 #include "nsStyleConsts.h"
 #include "nsContentUtils.h"
 #include "nsCSSColorUtils.h"
+#include "nsCSSRenderingGradients.h"
 #include "GeckoProfiler.h"
 #include "nsExpirationTracker.h"
 #include "RoundedRect.h"
 #include "nsIScriptError.h"
 #include "nsClassHashtable.h"
 #include "nsPresContext.h"
 #include "nsStyleStruct.h"
 #include "mozilla/gfx/2D.h"
@@ -3848,16 +3849,132 @@ nsCSSBorderImageRenderer::DrawBorderImag
                                                  unitSize, j * (RIGHT + 1) + i,
                                                  svgViewportSize, hasIntrinsicRatio);
     }
   }
 
   return result;
 }
 
+
+void
+nsCSSBorderImageRenderer::CreateWebRenderCommands(nsDisplayItem* aItem,
+                                                  nsIFrame* aForFrame,
+                                                  mozilla::wr::DisplayListBuilder& aBuilder,
+                                                  mozilla::wr::IpcResourceUpdateQueue& aResources,
+                                                  const mozilla::layers::StackingContextHelper& aSc,
+                                                  mozilla::layers::WebRenderLayerManager* aManager,
+                                                  nsDisplayListBuilder* aDisplayListBuilder)
+{
+  if (!mImageRenderer.IsReady()) {
+    return;
+  }
+
+  float widths[4];
+  float slice[4];
+  float outset[4];
+  const int32_t appUnitsPerDevPixel = aForFrame->PresContext()->AppUnitsPerDevPixel();
+  NS_FOR_CSS_SIDES(i) {
+    slice[i] = (float)(mSlice.Side(i)) / appUnitsPerDevPixel;
+    widths[i] = (float)(mWidths.Side(i)) / appUnitsPerDevPixel;
+    outset[i] = (float)(mImageOutset.Side(i)) / appUnitsPerDevPixel;
+  }
+
+  LayoutDeviceRect destRect = LayoutDeviceRect::FromAppUnits(
+    mArea, appUnitsPerDevPixel);
+  wr::LayoutRect dest = aSc.ToRelativeLayoutRect(destRect);
+
+  wr::LayoutRect clip = dest;
+  if (!mClip.IsEmpty()) {
+    LayoutDeviceRect clipRect = LayoutDeviceRect::FromAppUnits(
+      mClip, appUnitsPerDevPixel);
+    clip = aSc.ToRelativeLayoutRect(clipRect);
+  }
+
+  switch (mImageRenderer.GetType()) {
+    case eStyleImageType_Image:
+    {
+      uint32_t flags = aDisplayListBuilder->ShouldSyncDecodeImages() ?
+                       imgIContainer::FLAG_SYNC_DECODE :
+                       imgIContainer::FLAG_NONE;
+
+      RefPtr<imgIContainer> img = mImageRenderer.GetImage();
+      RefPtr<layers::ImageContainer> container = img->GetImageContainer(aManager, flags);
+      if (!container) {
+        return;
+      }
+
+      gfx::IntSize size;
+      Maybe<wr::ImageKey> key = aManager->CommandBuilder().CreateImageKey(aItem, container, aBuilder,
+                                                                          aResources, aSc, size);
+      if (key.isNothing()) {
+        return;
+      }
+
+      aBuilder.PushBorderImage(dest,
+                               clip,
+                               !aItem->BackfaceIsHidden(),
+                               wr::ToBorderWidths(widths[0], widths[1], widths[2], widths[3]),
+                               key.value(),
+                               wr::ToNinePatchDescriptor(
+                                 (float)(mImageSize.width) / appUnitsPerDevPixel,
+                                 (float)(mImageSize.height) / appUnitsPerDevPixel,
+                                 wr::ToSideOffsets2D_u32(slice[0], slice[1], slice[2], slice[3])),
+                               wr::ToSideOffsets2D_f32(outset[0], outset[1], outset[2], outset[3]),
+                               wr::ToRepeatMode(mRepeatModeHorizontal),
+                               wr::ToRepeatMode(mRepeatModeVertical));
+      break;
+    }
+    case eStyleImageType_Gradient:
+    {
+      RefPtr<nsStyleGradient> gradientData = mImageRenderer.GetGradientData();
+      nsCSSGradientRenderer renderer =
+        nsCSSGradientRenderer::Create(aForFrame->PresContext(), gradientData,
+                                      mImageSize);
+
+      wr::ExtendMode extendMode;
+      nsTArray<wr::GradientStop> stops;
+      LayoutDevicePoint lineStart;
+      LayoutDevicePoint lineEnd;
+      LayoutDeviceSize gradientRadius;
+      renderer.BuildWebRenderParameters(1.0, extendMode, stops, lineStart, lineEnd, gradientRadius);
+
+      if (gradientData->mShape == NS_STYLE_GRADIENT_SHAPE_LINEAR) {
+        LayerPoint startPoint = LayerPoint(dest.origin.x, dest.origin.y);
+        startPoint = startPoint + ViewAs<LayerPixel>(lineStart, PixelCastJustification::WebRenderHasUnitResolution);
+        LayerPoint endPoint = LayerPoint(dest.origin.x, dest.origin.y);
+        endPoint = endPoint + ViewAs<LayerPixel>(lineEnd, PixelCastJustification::WebRenderHasUnitResolution);
+
+        aBuilder.PushBorderGradient(dest,
+                                    clip,
+                                    !aItem->BackfaceIsHidden(),
+                                    wr::ToBorderWidths(widths[0], widths[1], widths[2], widths[3]),
+                                    wr::ToLayoutPoint(startPoint),
+                                    wr::ToLayoutPoint(endPoint),
+                                    stops,
+                                    extendMode,
+                                    wr::ToSideOffsets2D_f32(outset[0], outset[1], outset[2], outset[3]));
+      } else {
+        aBuilder.PushBorderRadialGradient(dest,
+                                          clip,
+                                          !aItem->BackfaceIsHidden(),
+                                          wr::ToBorderWidths(widths[0], widths[1], widths[2], widths[3]),
+                                          wr::ToLayoutPoint(lineStart),
+                                          wr::ToLayoutSize(gradientRadius),
+                                          stops,
+                                          extendMode,
+                                          wr::ToSideOffsets2D_f32(outset[0], outset[1], outset[2], outset[3]));
+      }
+      break;
+    }
+    default:
+      MOZ_ASSERT_UNREACHABLE("Unsupport border image type");
+  }
+}
+
 nsCSSBorderImageRenderer::nsCSSBorderImageRenderer(const nsCSSBorderImageRenderer& aRhs)
   : mImageRenderer(aRhs.mImageRenderer)
   , mImageSize(aRhs.mImageSize)
   , mSlice(aRhs.mSlice)
   , mWidths(aRhs.mWidths)
   , mImageOutset(aRhs.mImageOutset)
   , mArea(aRhs.mArea)
   , mClip(aRhs.mClip)
--- a/layout/painting/nsCSSRenderingBorders.h
+++ b/layout/painting/nsCSSRenderingBorders.h
@@ -304,16 +304,24 @@ public:
                             uint32_t aFlags,
                             mozilla::image::DrawResult* aDrawResult);
 
   mozilla::image::DrawResult
   DrawBorderImage(nsPresContext* aPresContext,
                   gfxContext& aRenderingContext,
                   nsIFrame* aForFrame,
                   const nsRect& aDirtyRect);
+  void
+  CreateWebRenderCommands(nsDisplayItem* aItem,
+                          nsIFrame* aForFrame,
+                          mozilla::wr::DisplayListBuilder& aBuilder,
+                          mozilla::wr::IpcResourceUpdateQueue& aResources,
+                          const mozilla::layers::StackingContextHelper& aSc,
+                          mozilla::layers::WebRenderLayerManager* aManager,
+                          nsDisplayListBuilder* aDisplayListBuilder);
 
   nsCSSBorderImageRenderer(const nsCSSBorderImageRenderer& aRhs);
   nsCSSBorderImageRenderer& operator=(const nsCSSBorderImageRenderer& aRhs);
 
 private:
   nsCSSBorderImageRenderer(nsIFrame* aForFrame,
                            const nsRect& aBorderArea,
                            const nsStyleBorder& aStyleBorder,
@@ -327,16 +335,17 @@ private:
   nsMargin mImageOutset;
   nsRect mArea;
   nsRect mClip;
   uint8_t mRepeatModeHorizontal;
   uint8_t mRepeatModeVertical;
   uint8_t mFill;
 
   friend class nsDisplayBorder;
+  friend struct nsCSSRendering;
 };
 
 namespace mozilla {
 #ifdef DEBUG_NEW_BORDERS
 #include <stdarg.h>
 
 static inline void PrintAsString(const mozilla::gfx::Point& p) {
   fprintf (stderr, "[%f,%f]", p.x, p.y);
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -4901,60 +4901,16 @@ nsDisplayBorder::GetLayerState(nsDisplay
   mBorderRenderer = Nothing();
   mBorderImageRenderer = Nothing();
   if ((!image ||
        image->GetType() != eStyleImageType_Image ||
        image->GetType() != eStyleImageType_Gradient) && !br) {
     return LAYER_NONE;
   }
 
-  LayersBackend backend = aManager->GetBackendType();
-  if (backend == layers::LayersBackend::LAYERS_WR) {
-    if (br) {
-      if (!br->CanCreateWebRenderCommands()) {
-        return LAYER_NONE;
-      }
-      mBorderRenderer = br;
-    } else {
-      if (styleBorder->mBorderImageRepeatH == NS_STYLE_BORDER_IMAGE_REPEAT_ROUND ||
-          styleBorder->mBorderImageRepeatH == NS_STYLE_BORDER_IMAGE_REPEAT_SPACE ||
-          styleBorder->mBorderImageRepeatV == NS_STYLE_BORDER_IMAGE_REPEAT_ROUND ||
-          styleBorder->mBorderImageRepeatV == NS_STYLE_BORDER_IMAGE_REPEAT_SPACE) {
-        // WebRender not supports this currently
-        return LAYER_NONE;
-      }
-
-      uint32_t flags = 0;
-      if (aBuilder->ShouldSyncDecodeImages()) {
-        flags |= nsImageRenderer::FLAG_SYNC_DECODE_IMAGES;
-      }
-
-      image::DrawResult result;
-      mBorderImageRenderer =
-        nsCSSBorderImageRenderer::CreateBorderImageRenderer(mFrame->PresContext(),
-                                                            mFrame,
-                                                            nsRect(offset, mFrame->GetSize()),
-                                                            *(mFrame->StyleContext()->StyleBorder()),
-                                                            mVisibleRect,
-                                                            mFrame->GetSkipSides(),
-                                                            flags,
-                                                            &result);
-
-      if (!mBorderImageRenderer) {
-        return LAYER_NONE;
-      }
-
-      if (!mBorderImageRenderer->mImageRenderer.IsImageContainerAvailable(aManager, flags)) {
-        return LAYER_NONE;
-      }
-    }
-
-    return LAYER_ACTIVE;
-  }
-
   if (!br) {
     return LAYER_NONE;
   }
 
   bool hasCompositeColors;
   if (!br->AllBordersSolid(&hasCompositeColors) || hasCompositeColors) {
     return LAYER_NONE;
   }
@@ -5017,29 +4973,26 @@ nsDisplayBorder::BuildLayer(nsDisplayLis
 
 bool
 nsDisplayBorder::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                          mozilla::wr::IpcResourceUpdateQueue& aResources,
                                          const StackingContextHelper& aSc,
                                          mozilla::layers::WebRenderLayerManager* aManager,
                                          nsDisplayListBuilder* aDisplayListBuilder)
 {
-  ContainerLayerParameters parameter;
-  if (GetLayerState(aDisplayListBuilder, aManager, parameter) != LAYER_ACTIVE) {
-    return false;
-  }
-
-  if (mBorderImageRenderer) {
-    CreateBorderImageWebRenderCommands(aBuilder, aResources, aSc,
-                                       aManager, aDisplayListBuilder);
-  } else if (mBorderRenderer) {
-    mBorderRenderer->CreateWebRenderCommands(aBuilder, aResources, aSc);
-  }
-
-  return true;
+  nsRect rect = nsRect(ToReferenceFrame(), mFrame->GetSize());
+
+  return nsCSSRendering::CreateWebRenderCommandsForBorder(this,
+                                                          mFrame,
+                                                          rect,
+                                                          aBuilder,
+                                                          aResources,
+                                                          aSc,
+                                                          aManager,
+                                                          aDisplayListBuilder);
 };
 
 void
 nsDisplayBorder::CreateBorderImageWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                                     mozilla::wr::IpcResourceUpdateQueue& aResources,
                                                     const StackingContextHelper& aSc,
                                                     mozilla::layers::WebRenderLayerManager* aManager,
                                                     nsDisplayListBuilder* aDisplayListBuilder)