Bug 1341101 part 3 - Support building WR gradients in nsCSSGradientRenderer r?jrmuizel,mattwoodrow draft
authorRyan Hunt <rhunt@eqrion.net>
Wed, 15 Mar 2017 03:20:02 -0400
changeset 501751 4f7ec68b3f1d8a524b7b0275913a26ace37185ac
parent 501740 4b19573e2b7c42e018ddb0841ba318936c18653b
child 501752 0c1ab830d8a66dbdb9e680ab73ad30d579f0c437
push id50111
push userbmo:rhunt@eqrion.net
push dateMon, 20 Mar 2017 22:48:03 +0000
reviewersjrmuizel, mattwoodrow
bugs1341101
milestone55.0a1
Bug 1341101 part 3 - Support building WR gradients in nsCSSGradientRenderer r?jrmuizel,mattwoodrow MozReview-Commit-ID: HLSmseHj5Si
gfx/webrender_bindings/WebRenderTypes.h
layout/painting/nsCSSRenderingGradients.cpp
layout/painting/nsCSSRenderingGradients.h
--- a/gfx/webrender_bindings/WebRenderTypes.h
+++ b/gfx/webrender_bindings/WebRenderTypes.h
@@ -143,16 +143,63 @@ static inline WrColor ToWrColor(const gf
   WrColor c;
   c.r = color.r;
   c.g = color.g;
   c.b = color.b;
   c.a = color.a;
   return c;
 }
 
+template<class T>
+static inline WrPoint ToWrPoint(const gfx::PointTyped<T>& point)
+{
+  WrPoint p;
+  p.x = point.x;
+  p.y = point.y;
+  return p;
+}
+
+template<class T>
+static inline WrPoint ToWrPoint(const gfx::IntPointTyped<T>& point)
+{
+  return ToWrPoint(IntPointToPoint(point));
+}
+
+template<class T>
+static inline WrRect ToWrRect(const gfx::RectTyped<T>& rect)
+{
+  WrRect r;
+  r.x = rect.x;
+  r.y = rect.y;
+  r.width = rect.width;
+  r.height = rect.height;
+  return r;
+}
+
+template<class T>
+static inline WrRect ToWrRect(const gfx::IntRectTyped<T>& rect)
+{
+  return ToWrRect(IntRectToRect(rect));
+}
+
+template<class T>
+static inline WrSize ToWrSize(const gfx::SizeTyped<T>& size)
+{
+  WrSize ls;
+  ls.width = size.width;
+  ls.height = size.height;
+  return ls;
+}
+
+template<class T>
+static inline WrSize ToWrSize(const gfx::IntSizeTyped<T>& size)
+{
+  return ToWrSize(IntSizeToSize(size));
+}
+
 static inline WrBorderStyle ToWrBorderStyle(const uint8_t& style)
 {
   switch (style) {
   case NS_STYLE_BORDER_STYLE_NONE:
     return WrBorderStyle::None;
   case NS_STYLE_BORDER_STYLE_SOLID:
     return WrBorderStyle::Solid;
   case NS_STYLE_BORDER_STYLE_DOUBLE:
@@ -180,32 +227,16 @@ static inline WrBorderStyle ToWrBorderSt
 static inline WrBorderSide ToWrBorderSide(const gfx::Color& color, const uint8_t& style)
 {
   WrBorderSide bs;
   bs.color = ToWrColor(color);
   bs.style = ToWrBorderStyle(style);
   return bs;
 }
 
-static inline WrPoint ToWrPoint(const LayerPoint point)
-{
-  WrPoint lp;
-  lp.x = point.x;
-  lp.y = point.y;
-  return lp;
-}
-
-static inline WrSize ToWrSize(const LayerSize size)
-{
-  WrSize ls;
-  ls.width = size.width;
-  ls.height = size.height;
-  return ls;
-}
-
 static inline WrBorderRadius ToWrBorderRadius(const LayerSize& topLeft, const LayerSize& topRight,
                                               const LayerSize& bottomLeft, const LayerSize& bottomRight)
 {
   WrBorderRadius br;
   br.top_left = ToWrSize(topLeft);
   br.top_right = ToWrSize(topRight);
   br.bottom_left = ToWrSize(bottomLeft);
   br.bottom_right = ToWrSize(bottomRight);
@@ -265,41 +296,16 @@ static inline WrRepeatMode ToWrRepeatMod
     return WrRepeatMode::Space;
   default:
     MOZ_ASSERT(false);
   }
 
   return WrRepeatMode::Stretch;
 }
 
-template<class T>
-static inline WrRect ToWrRect(const gfx::RectTyped<T>& rect)
-{
-  WrRect r;
-  r.x = rect.x;
-  r.y = rect.y;
-  r.width = rect.width;
-  r.height = rect.height;
-  return r;
-}
-
-template<class T>
-static inline WrRect ToWrRect(const gfx::IntRectTyped<T>& rect)
-{
-  return ToWrRect(IntRectToRect(rect));
-}
-
-static inline WrPoint ToWrPoint(const gfx::Point& point)
-{
-  WrPoint p;
-  p.x = point.x;
-  p.y = point.y;
-  return p;
-}
-
 static inline WrExternalImageId ToWrExternalImageId(uint64_t aID)
 {
   WrExternalImageId id;
   id.id = aID;
   return id;
 }
 
 struct VecU8 {
--- a/layout/painting/nsCSSRenderingGradients.cpp
+++ b/layout/painting/nsCSSRenderingGradients.cpp
@@ -24,16 +24,21 @@
 #include "gfxContext.h"
 #include "nsRenderingContext.h"
 #include "nsStyleStructInlines.h"
 #include "nsCSSProps.h"
 #include "mozilla/Telemetry.h"
 #include "gfxUtils.h"
 #include "gfxGradientCache.h"
 
+#include "mozilla/layers/WebRenderLayerManager.h"
+#include "mozilla/webrender/WebRenderTypes.h"
+#include "mozilla/webrender/WebRenderAPI.h"
+#include "Units.h"
+
 using namespace mozilla;
 using namespace mozilla::gfx;
 
 static gfxFloat
 ConvertGradientValueToPixels(const nsStyleCoord& aCoord,
                              gfxFloat aFillLength,
                              int32_t aAppUnitsPerPixel)
 {
@@ -1002,9 +1007,89 @@ nsCSSGradientRenderer::Paint(nsRendering
         ctx->SetPattern(gradientPattern);
       }
       ctx->Fill();
       ctx->SetMatrix(ctm);
     }
   }
 }
 
+void
+nsCSSGradientRenderer::BuildWebRenderDisplayItems(wr::DisplayListBuilder& aBuilder,
+                                                  layers::WebRenderDisplayItemLayer* aLayer,
+                                                  float aOpacity)
+{
+  bool isRepeat = mGradient->mRepeating || mForceRepeatToCoverTiles;
+  WrGradientExtendMode extendMode = isRepeat ? WrGradientExtendMode::Repeat : WrGradientExtendMode::Clamp;
+
+  nsTArray<WrGradientStop> stops(mStops.Length());
+  stops.SetLength(mStops.Length());
+  for(uint32_t i = 0; i < mStops.Length(); i++) {
+    stops[i].color.r = mStops[i].mColor.r;
+    stops[i].color.g = mStops[i].mColor.g;
+    stops[i].color.b = mStops[i].mColor.b;
+    stops[i].color.a = mStops[i].mColor.a * aOpacity;
+    stops[i].offset = mStops[i].mPosition;
+  }
+
+  double firstStop = mStops[0].mPosition;
+  double lastStop = mStops[mStops.Length() - 1].mPosition;
+
+  LayoutDevicePoint lineStart = LayoutDevicePoint(mLineStart.x, mLineStart.y);
+  LayoutDevicePoint lineEnd = LayoutDevicePoint(mLineEnd.x, mLineEnd.y);
+
+  // Do a naive tiling of the gradient by making multiple display items
+  // TODO: this should be done on the WebRender side eventually
+
+  nscoord appUnitsPerDevPixel = mPresContext->AppUnitsPerDevPixel();
+  LayoutDeviceRect firstTileBounds = LayoutDevicePixel::FromAppUnits(mDest, appUnitsPerDevPixel);
+  LayoutDeviceRect clipBounds = LayoutDevicePixel::FromAppUnits(mFillArea, appUnitsPerDevPixel);
+
+  // Make the units relative to the parent stacking context
+  firstTileBounds = LayoutDeviceRect::FromUnknownRect(aLayer->RelativeToParent(firstTileBounds.ToUnknownRect()));
+  clipBounds = LayoutDeviceRect::FromUnknownRect(aLayer->RelativeToParent(clipBounds.ToUnknownRect()));
+
+  float xStart = 0;
+  float yStart = 0;
+  float xEnd = (mFillArea.XMost() - mDest.X()) / appUnitsPerDevPixel;
+  float yEnd = (mFillArea.YMost() - mDest.Y()) / appUnitsPerDevPixel;
+
+  float stepX = mRepeatSize.width / appUnitsPerDevPixel;
+  float stepY = mRepeatSize.height / appUnitsPerDevPixel;
+
+  for (float y = yStart; y < yEnd; y += stepY) {
+    for (float x = xStart; x < xEnd; x += stepX) {
+      LayoutDevicePoint tileOffset = firstTileBounds.TopLeft() + LayoutDevicePoint(x, y);
+      LayoutDeviceRect tileRect = LayoutDeviceRect(tileOffset, firstTileBounds.Size());
+
+      if (mGradient->mShape == NS_STYLE_GRADIENT_SHAPE_LINEAR) {
+        LayoutDevicePoint relativeGradientStart = lineStart + tileOffset;
+        LayoutDevicePoint relativeGradientEnd = lineEnd + tileOffset;
+
+        aBuilder.PushLinearGradient(
+          mozilla::wr::ToWrRect(tileRect),
+          aBuilder.BuildClipRegion(mozilla::wr::ToWrRect(clipBounds)),
+          mozilla::wr::ToWrPoint(relativeGradientStart),
+          mozilla::wr::ToWrPoint(relativeGradientEnd),
+          stops,
+          extendMode);
+      } else {
+        LayoutDevicePoint relativeGradientCenter = lineStart + tileOffset;
+
+        // TODO: ellipse gradients
+        double innerRadius = mRadiusX * firstStop;
+        double outerRadius = mRadiusX * lastStop;
+
+        aBuilder.PushRadialGradient(
+          mozilla::wr::ToWrRect(tileRect),
+          aBuilder.BuildClipRegion(mozilla::wr::ToWrRect(clipBounds)),
+          mozilla::wr::ToWrPoint(relativeGradientCenter),
+          mozilla::wr::ToWrPoint(relativeGradientCenter),
+          innerRadius,
+          outerRadius,
+          stops,
+          extendMode);
+      }
+    }
+  }
+}
+
 } // namespace mozilla
--- a/layout/painting/nsCSSRenderingGradients.h
+++ b/layout/painting/nsCSSRenderingGradients.h
@@ -8,16 +8,24 @@
 
 #include "nsLayoutUtils.h"
 #include "nsStyleStruct.h"
 #include "Units.h"
 #include "mozilla/Maybe.h"
 
 namespace mozilla {
 
+namespace layers {
+class WebRenderDisplayItemLayer;
+} // namespace layers
+
+namespace wr {
+  class DisplayListBuilder;
+}
+
 // A resolved color stop, with a specific position along the gradient line and
 // a color.
 struct ColorStop {
   ColorStop(): mPosition(0), mIsMidpoint(false) {}
   ColorStop(double aPosition, bool aIsMidPoint, const Color& aColor) :
     mPosition(aPosition), mIsMidpoint(aIsMidPoint), mColor(aColor) {}
   double mPosition; // along the gradient line; 0=start, 1=end
   bool mIsMidpoint;
@@ -43,28 +51,32 @@ public:
                                              const nsSize& aRepeatSize,
                                              const mozilla::CSSIntRect& aSrc,
                                              const nsSize& aIntrinsiceSize);
 
   void Paint(nsRenderingContext& aRenderingContext,
              const nsRect& aDirtyRect,
              float aOpacity = 1.0);
 
+  void BuildWebRenderDisplayItems(wr::DisplayListBuilder& aBuilder,
+                                  layers::WebRenderDisplayItemLayer* aLayer,
+                                  float aOpacity = 1.0);
+
 private:
   nsCSSGradientRenderer() {}
 
   nsPresContext* mPresContext;
   nsStyleGradient* mGradient;
   CSSIntRect mSrc;
   nsRect mDest;
   nsRect mDirtyRect;
   nsRect mFillArea;
   nsSize mRepeatSize;
   nsTArray<ColorStop> mStops;
   gfxPoint mLineStart, mLineEnd;
-  double mRadiusX, mRadiusY;   // for radial gradients only
+  double mRadiusX, mRadiusY;
   bool mForceRepeatToCoverTiles;
   bool mForceRepeatToCoverTilesFlip;
 };
 
 } // namespace mozilla
 
 #endif /* nsCSSRenderingGradients_h__ */