Bug 1341101 part 5 - Support building WR DisplayItems for BackgroundImageLayers that are gradients r=mattwoodrow
authorRyan Hunt <rhunt@eqrion.net>
Mon, 20 Mar 2017 19:31:39 -0400
changeset 350154 65b02add807c5b1b482bc8924d77e6f503eab693
parent 350153 88a7b38645a04e4384a7906b04d42f38995458df
child 350155 5ccd13025da405c77702f572fd450522c826c669
push id88566
push userrhunt@eqrion.net
push dateTue, 28 Mar 2017 21:04:53 +0000
treeherdermozilla-inbound@5ccd13025da4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1341101
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 1341101 part 5 - Support building WR DisplayItems for BackgroundImageLayers that are gradients r=mattwoodrow MozReview-Commit-ID: BNLT8Wbp672
layout/painting/nsCSSRendering.cpp
layout/painting/nsCSSRendering.h
layout/painting/nsImageRenderer.cpp
layout/painting/nsImageRenderer.h
--- a/layout/painting/nsCSSRendering.cpp
+++ b/layout/painting/nsCSSRendering.cpp
@@ -1933,16 +1933,75 @@ nsCSSRendering::PaintStyleImageLayer(con
     }
 
     sc = aParams.frame->StyleContext();
   }
 
   return PaintStyleImageLayerWithSC(aParams, aRenderingCtx, sc, *aParams.frame->StyleBorder());
 }
 
+bool
+nsCSSRendering::CanBuildWebRenderDisplayItemsForStyleImageLayer(nsPresContext& aPresCtx,
+                                                                nsIFrame *aFrame,
+                                                                const nsStyleBackground* aBackgroundStyle,
+                                                                int32_t aLayer)
+{
+  if (!aBackgroundStyle) {
+    return false;
+  }
+
+  MOZ_ASSERT(aFrame &&
+             aLayer >= 0 &&
+             (uint32_t)aLayer < aBackgroundStyle->mImage.mLayers.Length());
+
+  // We cannot draw native themed backgrounds
+  const nsStyleDisplay* displayData = aFrame->StyleDisplay();
+  if (displayData->UsedAppearance()) {
+    nsITheme *theme = aPresCtx.GetTheme();
+    if (theme && theme->ThemeSupportsWidget(&aPresCtx,
+                                            aFrame,
+                                            displayData->UsedAppearance())) {
+      return false;
+    }
+  }
+
+  // We only support painting gradients for a single style image layer
+  return aBackgroundStyle->mImage.mLayers[aLayer].mImage.GetType() == eStyleImageType_Gradient;
+}
+
+void
+nsCSSRendering::BuildWebRenderDisplayItemsForStyleImageLayer(const PaintBGParams& aParams,
+                                                             mozilla::wr::DisplayListBuilder& aBuilder,
+                                                             mozilla::layers::WebRenderDisplayItemLayer* aLayer)
+{
+  NS_PRECONDITION(aParams.frame,
+                  "Frame is expected to be provided to BuildWebRenderDisplayItemsForStyleImageLayer");
+
+  nsStyleContext *sc;
+  if (!FindBackground(aParams.frame, &sc)) {
+    // We don't want to bail out if moz-appearance is set on a root
+    // node. If it has a parent content node, bail because it's not
+    // a root, otherwise keep going in order to let the theme stuff
+    // draw the background. The canvas really should be drawing the
+    // bg, but there's no way to hook that up via css.
+    if (!aParams.frame->StyleDisplay()->UsedAppearance()) {
+      return;
+    }
+
+    nsIContent* content = aParams.frame->GetContent();
+    if (!content || content->GetParent()) {
+      return;
+    }
+
+    sc = aParams.frame->StyleContext();
+  }
+
+  return BuildWebRenderDisplayItemsForStyleImageLayerWithSC(aParams, aBuilder, aLayer, sc, *aParams.frame->StyleBorder());
+}
+
 static bool
 IsOpaqueBorderEdge(const nsStyleBorder& aBorder, mozilla::Side aSide)
 {
   if (aBorder.GetComputedBorder().Side(aSide) == 0)
     return true;
   switch (aBorder.GetBorderStyle(aSide)) {
   case NS_STYLE_BORDER_STYLE_SOLID:
   case NS_STYLE_BORDER_STYLE_GROOVE:
@@ -2642,16 +2701,71 @@ nsCSSRendering::PaintStyleImageLayerWith
         ctx->SetOp(CompositionOp::OP_OVER);
       }
     }
   }
 
   return result;
 }
 
+void
+nsCSSRendering::BuildWebRenderDisplayItemsForStyleImageLayerWithSC(const PaintBGParams& aParams,
+                                                                   mozilla::wr::DisplayListBuilder& aBuilder,
+                                                                   mozilla::layers::WebRenderDisplayItemLayer* aLayer,
+                                                                   nsStyleContext *aBackgroundSC,
+                                                                   const nsStyleBorder& aBorder)
+{
+  MOZ_ASSERT(CanBuildWebRenderDisplayItemsForStyleImageLayer(aParams.presCtx,
+                                                             aParams.frame,
+                                                             aBackgroundSC->StyleBackground(),
+                                                             aParams.layer));
+
+  MOZ_ASSERT(!(aParams.paintFlags & PAINTBG_MASK_IMAGE));
+
+  nscoord appUnitsPerPixel = aParams.presCtx.AppUnitsPerDevPixel();
+  ImageLayerClipState clipState;
+
+  clipState.mBGClipArea = *aParams.bgClipRect;
+  clipState.mCustomClip = true;
+  clipState.mHasRoundedCorners = false;
+  SetupDirtyRects(clipState.mBGClipArea, aParams.dirtyRect, appUnitsPerPixel,
+                  &clipState.mDirtyRectInAppUnits,
+                  &clipState.mDirtyRectInDevPx);
+
+  // Compute the outermost boundary of the area that might be painted.
+  // Same coordinate space as aParams.borderArea & aParams.bgClipRect.
+  Sides skipSides = aParams.frame->GetSkipSides();
+  nsRect paintBorderArea =
+    ::BoxDecorationRectForBackground(aParams.frame, aParams.borderArea,
+                                     skipSides, &aBorder);
+
+  const nsStyleImageLayers& layers = aBackgroundSC->StyleBackground()->mImage;
+  const nsStyleImageLayers::Layer& layer = layers.mLayers[aParams.layer];
+
+  // Skip the following layer painting code if we found the dirty region is
+  // empty or the current layer is not selected for drawing.
+  if (clipState.mDirtyRectInDevPx.IsEmpty()) {
+    return;
+  }
+
+  nsBackgroundLayerState state =
+    PrepareImageLayer(&aParams.presCtx, aParams.frame,
+                      aParams.paintFlags, paintBorderArea,
+                      clipState.mBGClipArea, layer, nullptr);
+
+  if (!state.mFillArea.IsEmpty()) {
+    state.mImageRenderer.BuildWebRenderDisplayItemsForLayer(&aParams.presCtx,
+                                   aBuilder, aLayer,
+                                   state.mDestArea, state.mFillArea,
+                                   state.mAnchor + paintBorderArea.TopLeft(),
+                                   clipState.mDirtyRectInAppUnits,
+                                   state.mRepeatSize, aParams.opacity);
+  }
+}
+
 nsRect
 nsCSSRendering::ComputeImageLayerPositioningArea(nsPresContext* aPresContext,
                                                  nsIFrame* aForFrame,
                                                  const nsRect& aBorderArea,
                                                  const nsStyleImageLayers::Layer& aLayer,
                                                  nsIFrame** aAttachedToFrame,
                                                  bool* aOutIsTransformedFixed)
 {
--- a/layout/painting/nsCSSRendering.h
+++ b/layout/painting/nsCSSRendering.h
@@ -28,18 +28,23 @@ namespace mozilla {
 
 namespace gfx {
 struct Color;
 class DrawTarget;
 } // namespace gfx
 
 namespace layers {
 class ImageContainer;
+class WebRenderDisplayItemLayer;
 } // namespace layers
 
+namespace wr {
+class DisplayListBuilder;
+} // namespace wr
+
 enum class PaintBorderFlags : uint8_t
 {
   SYNC_DECODE_IMAGES = 1 << 0
 };
 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(PaintBorderFlags)
 
 } // namespace mozilla
 
@@ -445,17 +450,16 @@ struct nsCSSRendering {
        layer(aLayer),
        compositionOp(aCompositionOp),
        opacity(aOpacity) {}
   };
 
   static DrawResult PaintStyleImageLayer(const PaintBGParams& aParams,
                                          nsRenderingContext& aRenderingCtx);
 
-
   /**
    * Same as |PaintStyleImageLayer|, except using the provided style structs.
    * This short-circuits the code that ensures that the root element's
    * {background|mask} is drawn on the canvas.
    * The aLayer parameter allows you to paint a single layer of the
    * {background|mask}.
    * The default value for aLayer, -1, means that all layers will be painted.
    * The background color will only be painted if the back-most layer is also
@@ -464,16 +468,30 @@ struct nsCSSRendering {
    * If all layers are painted, the image layer's blend mode (or the mask
    * layer's composition mode) will be used.
    */
   static DrawResult PaintStyleImageLayerWithSC(const PaintBGParams& aParams,
                                                nsRenderingContext& aRenderingCtx,
                                                nsStyleContext *mBackgroundSC,
                                                const nsStyleBorder& aBorder);
 
+  static bool CanBuildWebRenderDisplayItemsForStyleImageLayer(nsPresContext& aPresCtx,
+                                                              nsIFrame *aFrame,
+                                                              const nsStyleBackground* aBackgroundStyle,
+                                                              int32_t aLayer);
+  static void BuildWebRenderDisplayItemsForStyleImageLayer(const PaintBGParams& aParams,
+                                                           mozilla::wr::DisplayListBuilder& aBuilder,
+                                                           mozilla::layers::WebRenderDisplayItemLayer* aLayer);
+
+  static void BuildWebRenderDisplayItemsForStyleImageLayerWithSC(const PaintBGParams& aParams,
+                                                                 mozilla::wr::DisplayListBuilder& aBuilder,
+                                                                 mozilla::layers::WebRenderDisplayItemLayer* aLayer,
+                                                                 nsStyleContext *mBackgroundSC,
+                                                                 const nsStyleBorder& aBorder);
+
   /**
    * Returns the rectangle covered by the given background layer image, taking
    * into account background positioning, sizing, and repetition, but not
    * clipping.
    */
   static nsRect GetBackgroundLayerRect(nsPresContext* aPresContext,
                                        nsIFrame* aForFrame,
                                        const nsRect& aBorderArea,
--- a/layout/painting/nsImageRenderer.cpp
+++ b/layout/painting/nsImageRenderer.cpp
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* utility functions for drawing borders and backgrounds */
 
 #include "nsImageRenderer.h"
 #include "nsCSSRenderingGradients.h"
+#include "mozilla/webrender/WebRenderAPI.h"
 
 nsSize
 CSSSizeOrRatio::ComputeConcreteSize() const
 {
   NS_ASSERTION(CanComputeConcreteSize(), "Cannot compute");
   if (mHasWidth && mHasHeight) {
     return nsSize(mWidth, mHeight);
   }
@@ -438,17 +439,16 @@ RGBALuminanceOperation(uint8_t *aData,
       *pixel = (((((*pixel & 0x00FF0000) >> 16) * redFactor) +
                  (((*pixel & 0x0000FF00) >>  8) * greenFactor) +
                   ((*pixel & 0x000000FF)        * blueFactor)) >> 8) << 24;
       pixel++;
     }
   }
 }
 
-
 DrawResult
 nsImageRenderer::Draw(nsPresContext*       aPresContext,
                       nsRenderingContext&  aRenderingContext,
                       const nsRect&        aDirtyRect,
                       const nsRect&        aDest,
                       const nsRect&        aFill,
                       const nsPoint&       aAnchor,
                       const nsSize&        aRepeatSize,
@@ -559,16 +559,54 @@ nsImageRenderer::Draw(nsPresContext*    
                     Rect(0, 0, tmpDTRect.width, tmpDTRect.height),
                     DrawSurfaceOptions(SamplingFilter::POINT),
                     DrawOptions(1.0f, aRenderingContext.ThebesContext()->CurrentOp()));
   }
 
   return result;
 }
 
+void
+nsImageRenderer::BuildWebRenderDisplayItems(nsPresContext*       aPresContext,
+                                            mozilla::wr::DisplayListBuilder&            aBuilder,
+                                            mozilla::layers::WebRenderDisplayItemLayer* aLayer,
+                                            const nsRect&        aDirtyRect,
+                                            const nsRect&        aDest,
+                                            const nsRect&        aFill,
+                                            const nsPoint&       aAnchor,
+                                            const nsSize&        aRepeatSize,
+                                            const CSSIntRect&    aSrc,
+                                            float                aOpacity)
+{
+  if (!IsReady()) {
+    NS_NOTREACHED("Ensure PrepareImage() has returned true before calling me");
+    return;
+  }
+  if (aDest.IsEmpty() || aFill.IsEmpty() ||
+      mSize.width <= 0 || mSize.height <= 0) {
+    return;
+  }
+
+  switch (mType) {
+    case eStyleImageType_Gradient:
+    {
+      Maybe<nsCSSGradientRenderer> renderer =
+        nsCSSGradientRenderer::Create(aPresContext, mGradientData,
+                                   aDest, aFill, aRepeatSize, aSrc, mSize);
+
+      if (renderer) {
+        renderer->BuildWebRenderDisplayItems(aBuilder, aLayer, aOpacity);
+      }
+      break;
+    }
+    default:
+      break;
+  }
+}
+
 already_AddRefed<gfxDrawable>
 nsImageRenderer::DrawableForElement(const nsRect& aImageRect,
                                     gfxContext&  aContext)
 {
   NS_ASSERTION(mType == eStyleImageType_Element,
                "DrawableForElement only makes sense if backed by an element");
   if (mPaintServerFrame) {
     // XXX(seth): In order to not pass FLAG_SYNC_DECODE_IMAGES here,
@@ -619,16 +657,44 @@ nsImageRenderer::DrawLayer(nsPresContext
   return Draw(aPresContext, aRenderingContext,
               aDirty, aDest, aFill, aAnchor, aRepeatSize,
               CSSIntRect(0, 0,
                          nsPresContext::AppUnitsToIntCSSPixels(mSize.width),
                          nsPresContext::AppUnitsToIntCSSPixels(mSize.height)),
               aOpacity);
 }
 
+void
+nsImageRenderer::BuildWebRenderDisplayItemsForLayer(nsPresContext*       aPresContext,
+                                                    mozilla::wr::DisplayListBuilder& aBuilder,
+                                                    WebRenderDisplayItemLayer*       aLayer,
+                                                    const nsRect&        aDest,
+                                                    const nsRect&        aFill,
+                                                    const nsPoint&       aAnchor,
+                                                    const nsRect&        aDirty,
+                                                    const nsSize&        aRepeatSize,
+                                                    float                aOpacity)
+{
+  if (!IsReady()) {
+    NS_NOTREACHED("Ensure PrepareImage() has returned true before calling me");
+    return;
+  }
+  if (aDest.IsEmpty() || aFill.IsEmpty() ||
+      mSize.width <= 0 || mSize.height <= 0) {
+    return;
+  }
+
+  BuildWebRenderDisplayItems(aPresContext, aBuilder, aLayer,
+                             aDirty, aDest, aFill, aAnchor, aRepeatSize,
+                             CSSIntRect(0, 0,
+                                        nsPresContext::AppUnitsToIntCSSPixels(mSize.width),
+                                        nsPresContext::AppUnitsToIntCSSPixels(mSize.height)),
+                             aOpacity);
+}
+
 /**
  * Compute the size and position of the master copy of the image. I.e., a single
  * tile used to fill the dest rect.
  * aFill The destination rect to be filled
  * aHFill and aVFill are the repeat patterns for the component -
  * NS_STYLE_BORDER_IMAGE_REPEAT_* - i.e., how a tiling unit is used to fill aFill
  * aUnitSize The size of the source rect in dest coords.
  */
--- a/layout/painting/nsImageRenderer.h
+++ b/layout/painting/nsImageRenderer.h
@@ -8,16 +8,24 @@
 
 #include "nsLayoutUtils.h"
 #include "nsStyleStruct.h"
 #include "Units.h"
 
 class gfxDrawable;
 namespace mozilla {
 
+namespace layers {
+class WebRenderDisplayItemLayer;
+} // namespace layers
+
+namespace wr {
+class DisplayListBuilder;
+} // namespace wr
+
 // A CSSSizeOrRatio represents a (possibly partially specified) size for use
 // in computing image sizes. Either or both of the width and height might be
 // given. A ratio of width to height may also be given. If we at least two
 // of these then we can compute a concrete size, that is a width and height.
 struct CSSSizeOrRatio
 {
   CSSSizeOrRatio()
     : mRatio(0, 0)
@@ -188,16 +196,31 @@ public:
                        const nsRect&        aDest,
                        const nsRect&        aFill,
                        const nsPoint&       aAnchor,
                        const nsRect&        aDirty,
                        const nsSize&        aRepeatSize,
                        float                aOpacity);
 
   /**
+   * Builds WebRender DisplayItems for an image using
+   * {background|mask}-specific arguments.
+   * @see nsLayoutUtils::DrawImage() for parameters.
+   */
+  void BuildWebRenderDisplayItemsForLayer(nsPresContext*       aPresContext,
+                                          mozilla::wr::DisplayListBuilder& aBuilder,
+                                          mozilla::layers::WebRenderDisplayItemLayer* aLayer,
+                                          const nsRect&        aDest,
+                                          const nsRect&        aFill,
+                                          const nsPoint&       aAnchor,
+                                          const nsRect&        aDirty,
+                                          const nsSize&        aRepeatSize,
+                                          float                aOpacity);
+
+  /**
    * Draw the image to a single component of a border-image style rendering.
    * aFill The destination rect to be drawn into
    * aSrc is the part of the image to be rendered into a tile (aUnitSize in
    * aFill), if aSrc and the dest tile are different sizes, the image will be
    * scaled to map aSrc onto the dest tile.
    * aHFill and aVFill are the repeat patterns for the component -
    * NS_STYLE_BORDER_IMAGE_REPEAT_*
    * aUnitSize The scaled size of a single source rect (in destination coords)
@@ -252,16 +275,34 @@ private:
                   const nsRect&        aDest,
                   const nsRect&        aFill,
                   const nsPoint&       aAnchor,
                   const nsSize&        aRepeatSize,
                   const mozilla::CSSIntRect& aSrc,
                   float                aOpacity = 1.0);
 
   /**
+   * Builds WebRender DisplayItems for the image.
+   * aSrc is a rect on the source image which will be mapped to aDest; it's
+   * currently only used for gradients.
+   *
+   * @see nsLayoutUtils::DrawImage() for other parameters.
+   */
+  void BuildWebRenderDisplayItems(nsPresContext*       aPresContext,
+                                  mozilla::wr::DisplayListBuilder& aBuilder,
+                                  mozilla::layers::WebRenderDisplayItemLayer* aLayer,
+                                  const nsRect&        aDirtyRect,
+                                  const nsRect&        aDest,
+                                  const nsRect&        aFill,
+                                  const nsPoint&       aAnchor,
+                                  const nsSize&        aRepeatSize,
+                                  const mozilla::CSSIntRect& aSrc,
+                                  float                aOpacity = 1.0);
+
+  /**
    * Helper method for creating a gfxDrawable from mPaintServerFrame or
    * mImageElementSurface.
    * Requires mType is eStyleImageType_Element.
    * Returns null if we cannot create the drawable.
    */
   already_AddRefed<gfxDrawable> DrawableForElement(const nsRect& aImageRect,
                                                    gfxContext&  aContext);