Bug 1341101 part 3 - Support building WR gradients in nsCSSGradientRenderer r=mattwoodrow
authorRyan Hunt <rhunt@eqrion.net>
Wed, 15 Mar 2017 03:20:02 -0400
changeset 350269 5f5fef49b82c0c97bc403c8936f3ff7800416808
parent 350268 d82968c4e2921cfb4ca5a7f746c8ac46f15dd370
child 350270 88a7b38645a04e4384a7906b04d42f38995458df
push id31570
push userryanvm@gmail.com
push dateWed, 29 Mar 2017 13:42:06 +0000
treeherdermozilla-central@6ea713ccc9ab [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 3 - Support building WR gradients in nsCSSGradientRenderer r=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
@@ -157,16 +157,71 @@ 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));
+}
+
+static inline WrPoint ToWrPoint(const gfx::Point& point)
+{
+  WrPoint p;
+  p.x = point.x;
+  p.y = point.y;
+  return p;
+}
+
+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:
@@ -194,32 +249,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 ToWrUniformBorderRadius(const LayerSize& aSize)
 {
   WrBorderRadius br;
   br.top_left = ToWrSize(aSize);
   br.top_right = ToWrSize(aSize);
   br.bottom_left = ToWrSize(aSize);
   br.bottom_right = ToWrSize(aSize);
   return br;
@@ -290,50 +329,25 @@ static inline WrRepeatMode ToWrRepeatMod
   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));
-}
-
-template<class T>
 static inline WrComplexClipRegion ToWrComplexClipRegion(const gfx::RectTyped<T>& rect,
                                                         const LayerSize& size)
 {
   WrComplexClipRegion complex_clip;
   complex_clip.rect = wr::ToWrRect(rect);
   complex_clip.radii = wr::ToWrUniformBorderRadius(size);
   return complex_clip;
 }
 
-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)
 {
@@ -998,9 +1003,89 @@ nsCSSGradientRenderer::Paint(gfxContext&
         aContext.SetPattern(gradientPattern);
       }
       aContext.Fill();
       aContext.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(gfxContext& aContext,
              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__ */