Bug 1347469 - Add support for gradient border. r=mattwoodrow

MozReview-Commit-ID: 7RfVsPFWhlo
This commit is contained in:
Morris Tseng 2017-04-10 17:27:30 +08:00
parent d4a7aaf673
commit 5cb5800c6b
5 changed files with 141 additions and 57 deletions

View File

@ -1011,27 +1011,42 @@ nsCSSGradientRenderer::Paint(gfxContext& aContext,
}
}
void
nsCSSGradientRenderer::BuildWebRenderParameters(float aOpacity,
WrGradientExtendMode& aMode,
nsTArray<WrGradientStop>& aStops,
LayoutDevicePoint& aLineStart,
LayoutDevicePoint& aLineEnd,
LayoutDeviceSize& aGradientRadius)
{
bool isRepeat = mGradient->mRepeating || mForceRepeatToCoverTiles;
aMode = isRepeat ? WrGradientExtendMode::Repeat : WrGradientExtendMode::Clamp;
aStops.SetLength(mStops.Length());
for(uint32_t i = 0; i < mStops.Length(); i++) {
aStops[i].color.r = mStops[i].mColor.r;
aStops[i].color.g = mStops[i].mColor.g;
aStops[i].color.b = mStops[i].mColor.b;
aStops[i].color.a = mStops[i].mColor.a * aOpacity;
aStops[i].offset = mStops[i].mPosition;
}
aLineStart = LayoutDevicePoint(mLineStart.x, mLineStart.y);
aLineEnd = LayoutDevicePoint(mLineEnd.x, mLineEnd.y);
aGradientRadius = LayoutDeviceSize(mRadiusX, mRadiusY);
}
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;
}
LayoutDevicePoint lineStart = LayoutDevicePoint(mLineStart.x, mLineStart.y);
LayoutDevicePoint lineEnd = LayoutDevicePoint(mLineEnd.x, mLineEnd.y);
LayoutDeviceSize gradientRadius = LayoutDeviceSize(mRadiusX, mRadiusY);
WrGradientExtendMode extendMode;
nsTArray<WrGradientStop> stops;
LayoutDevicePoint lineStart;
LayoutDevicePoint lineEnd;
LayoutDeviceSize gradientRadius;
BuildWebRenderParameters(aOpacity, extendMode, stops, lineStart, lineEnd, gradientRadius);
// Do a naive tiling of the gradient by making multiple display items
// TODO: this should be done on the WebRender side eventually

View File

@ -57,6 +57,13 @@ public:
const nsRect& aDirtyRect,
float aOpacity = 1.0);
void BuildWebRenderParameters(float aOpacity,
WrGradientExtendMode& aMode,
nsTArray<WrGradientStop>& aStops,
LayoutDevicePoint& aLineStart,
LayoutDevicePoint& aLineEnd,
LayoutDeviceSize& aGradientRadius);
void BuildWebRenderDisplayItems(wr::DisplayListBuilder& aBuilder,
layers::WebRenderDisplayItemLayer* aLayer,
float aOpacity = 1.0);

View File

@ -4610,7 +4610,9 @@ nsDisplayBorder::GetLayerState(nsDisplayListBuilder* aBuilder,
const nsStyleImage* image = &styleBorder->mBorderImageSource;
mBorderRenderer = Nothing();
mBorderImageRenderer = Nothing();
if ((!image || image->GetType() != eStyleImageType_Image) && !br) {
if ((!image ||
image->GetType() != eStyleImageType_Image ||
image->GetType() != eStyleImageType_Gradient) && !br) {
return LAYER_NONE;
}
@ -4728,29 +4730,21 @@ nsDisplayBorder::CreateBorderImageWebRenderCommands(mozilla::wr::DisplayListBuil
nsTArray<WebRenderParentCommand>& aParentCommands,
WebRenderDisplayItemLayer* aLayer)
{
// Only support border-image currently
MOZ_ASSERT(mBorderImageRenderer);
if (!mBorderImageRenderer->mImageRenderer.IsReady()) {
return;
}
nsDisplayListBuilder* builder = aLayer->GetDisplayListBuilder();
uint32_t flags = builder->ShouldSyncDecodeImages() ?
imgIContainer::FLAG_SYNC_DECODE :
imgIContainer::FLAG_NONE;
RefPtr<imgIContainer> img = mBorderImageRenderer->mImageRenderer.GetImage();
RefPtr<layers::ImageContainer> container = img->GetImageContainer(aLayer->WrManager(), flags);
if (!container) {
return;
}
uint64_t externalImageId = aLayer->SendImageContainer(container);
if (!externalImageId) {
return;
}
float widths[4];
float slice[4];
float outset[4];
const int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
NS_FOR_CSS_SIDES(i) {
slice[i] = (float)(mBorderImageRenderer->mSlice.Side(i)) / appUnitsPerDevPixel;
widths[i] = (float)(mBorderImageRenderer->mWidths.Side(i)) / appUnitsPerDevPixel;
outset[i] = (float)(mBorderImageRenderer->mImageOutset.Side(i)) / appUnitsPerDevPixel;
}
Rect destRect =
NSRectToRect(mBorderImageRenderer->mArea, appUnitsPerDevPixel);
Rect destRectTransformed = aLayer->RelativeToParent(destRect);
@ -4764,30 +4758,89 @@ nsDisplayBorder::CreateBorderImageWebRenderCommands(mozilla::wr::DisplayListBuil
clip = RoundedToInt(clipRectTransformed);
}
float widths[4];
float slice[4];
float outset[4];
NS_FOR_CSS_SIDES(i) {
slice[i] = (float)(mBorderImageRenderer->mSlice.Side(i)) / appUnitsPerDevPixel;
widths[i] = (float)(mBorderImageRenderer->mWidths.Side(i)) / appUnitsPerDevPixel;
outset[i] = (float)(mBorderImageRenderer->mImageOutset.Side(i)) / appUnitsPerDevPixel;
}
switch (mBorderImageRenderer->mImageRenderer.GetType()) {
case eStyleImageType_Image:
{
nsDisplayListBuilder* builder = aLayer->GetDisplayListBuilder();
uint32_t flags = builder->ShouldSyncDecodeImages() ?
imgIContainer::FLAG_SYNC_DECODE :
imgIContainer::FLAG_NONE;
WrImageKey key;
key.mNamespace = aLayer->WrBridge()->GetNamespace();
key.mHandle = aLayer->WrBridge()->GetNextResourceId();
aParentCommands.AppendElement(OpAddExternalImage(externalImageId, key));
aBuilder.PushBorderImage(wr::ToWrRect(dest),
aBuilder.BuildClipRegion(wr::ToWrRect(clip)),
wr::ToWrBorderWidths(widths[0], widths[1], widths[2], widths[3]),
key,
wr::ToWrNinePatchDescriptor(
(float)(mBorderImageRenderer->mImageSize.width) / appUnitsPerDevPixel,
(float)(mBorderImageRenderer->mImageSize.height) / appUnitsPerDevPixel,
wr::ToWrSideOffsets2Du32(slice[0], slice[1], slice[2], slice[3])),
wr::ToWrSideOffsets2Df32(outset[0], outset[1], outset[2], outset[3]),
wr::ToWrRepeatMode(mBorderImageRenderer->mRepeatModeHorizontal),
wr::ToWrRepeatMode(mBorderImageRenderer->mRepeatModeVertical));
RefPtr<imgIContainer> img = mBorderImageRenderer->mImageRenderer.GetImage();
RefPtr<layers::ImageContainer> container = img->GetImageContainer(aLayer->WrManager(), flags);
if (!container) {
return;
}
uint64_t externalImageId = aLayer->SendImageContainer(container);
if (!externalImageId) {
return;
}
WrImageKey key;
key.mNamespace = aLayer->WrBridge()->GetNamespace();
key.mHandle = aLayer->WrBridge()->GetNextResourceId();
aParentCommands.AppendElement(OpAddExternalImage(externalImageId, key));
aBuilder.PushBorderImage(wr::ToWrRect(dest),
aBuilder.BuildClipRegion(wr::ToWrRect(clip)),
wr::ToWrBorderWidths(widths[0], widths[1], widths[2], widths[3]),
key,
wr::ToWrNinePatchDescriptor(
(float)(mBorderImageRenderer->mImageSize.width) / appUnitsPerDevPixel,
(float)(mBorderImageRenderer->mImageSize.height) / appUnitsPerDevPixel,
wr::ToWrSideOffsets2Du32(slice[0], slice[1], slice[2], slice[3])),
wr::ToWrSideOffsets2Df32(outset[0], outset[1], outset[2], outset[3]),
wr::ToWrRepeatMode(mBorderImageRenderer->mRepeatModeHorizontal),
wr::ToWrRepeatMode(mBorderImageRenderer->mRepeatModeVertical));
break;
}
case eStyleImageType_Gradient:
{
RefPtr<nsStyleGradient> gradientData = mBorderImageRenderer->mImageRenderer.GetGradientData();
Maybe<nsCSSGradientRenderer> renderer =
nsCSSGradientRenderer::Create(mFrame->PresContext(), gradientData,
mBorderImageRenderer->mArea,
mBorderImageRenderer->mArea,
mBorderImageRenderer->mArea.Size(),
CSSIntRect(),
mBorderImageRenderer->mImageSize);
WrGradientExtendMode extendMode;
nsTArray<WrGradientStop> stops;
LayoutDevicePoint lineStart;
LayoutDevicePoint lineEnd;
LayoutDeviceSize gradientRadius;
renderer->BuildWebRenderParameters(1.0, extendMode, stops, lineStart, lineEnd, gradientRadius);
if (gradientData->mShape == NS_STYLE_GRADIENT_SHAPE_LINEAR) {
Point startPoint = dest.TopLeft();
startPoint = startPoint + Point(lineStart.x, lineStart.y);
Point endPoint = dest.TopLeft();
endPoint = endPoint + Point(lineEnd.x, lineEnd.y);
aBuilder.PushBorderGradient(wr::ToWrRect(dest),
aBuilder.BuildClipRegion(wr::ToWrRect(clip)),
wr::ToWrBorderWidths(widths[0], widths[1], widths[2], widths[3]),
wr::ToWrPoint(startPoint),
wr::ToWrPoint(endPoint),
stops,
extendMode,
wr::ToWrSideOffsets2Df32(outset[0], outset[1], outset[2], outset[3]));
} else {
aBuilder.PushBorderRadialGradient(wr::ToWrRect(dest),
aBuilder.BuildClipRegion(wr::ToWrRect(clip)),
wr::ToWrBorderWidths(widths[0], widths[1], widths[2], widths[3]),
wr::ToWrPoint(lineStart),
wr::ToWrSize(gradientRadius),
stops,
extendMode,
wr::ToWrSideOffsets2Df32(outset[0], outset[1], outset[2], outset[3]));
}
break;
}
default:
MOZ_ASSERT_UNREACHABLE("Unsupport border image type");
}
}
void

View File

@ -999,3 +999,10 @@ nsImageRenderer::PurgeCacheForViewportChange(
}
}
already_AddRefed<nsStyleGradient>
nsImageRenderer::GetGradientData()
{
RefPtr<nsStyleGradient> res = mGradientData;
return res.forget();
}

View File

@ -262,6 +262,8 @@ public:
void SetMaskOp(uint8_t aMaskOp) { mMaskOp = aMaskOp; }
void PurgeCacheForViewportChange(const mozilla::Maybe<nsSize>& aSVGViewportSize,
const bool aHasRatio);
nsStyleImageType GetType() const { return mType; }
already_AddRefed<nsStyleGradient> GetGradientData();
private:
/**