Bug 1341101 part 3 - Support building WR gradients in nsCSSGradientRenderer r=mattwoodrow
MozReview-Commit-ID: HLSmseHj5Si
--- 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__ */