зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1615862 - Handle conic-gradients in nsCSSGradientRenderer for WebRender. r=emilio,mstange
Differential Revision: https://phabricator.services.mozilla.com/D63018 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
374e0856d0
Коммит
378e9808bf
|
@ -3663,18 +3663,21 @@ ImgDrawResult nsCSSBorderImageRenderer::CreateWebRenderCommands(
|
|||
bool noVerticalBorders = widths[0] <= epsilon && widths[2] < epsilon;
|
||||
bool noHorizontalBorders = widths[1] <= epsilon && widths[3] < epsilon;
|
||||
|
||||
// Border image with no border. It's a little silly but WebRender currently does
|
||||
// not handle this. We could fall back to a blob image but there are reftests that
|
||||
// are sensible to the test going through a blob while the reference doesn't.
|
||||
// Border image with no border. It's a little silly but WebRender
|
||||
// currently does not handle this. We could fall back to a blob image
|
||||
// but there are reftests that are sensible to the test going through a
|
||||
// blob while the reference doesn't.
|
||||
if (noVerticalBorders && noHorizontalBorders) {
|
||||
aBuilder.PushImage(dest, clip, !aItem->BackfaceIsHidden(), rendering, key.value());
|
||||
aBuilder.PushImage(dest, clip, !aItem->BackfaceIsHidden(), rendering,
|
||||
key.value());
|
||||
break;
|
||||
}
|
||||
|
||||
// Fall-back if we want to fill the middle area and opposite edges are
|
||||
// both empty.
|
||||
// TODO(bug 1609893): moving some of the repetition handling code out
|
||||
// of the image shader will make it easier to handle these cases properly.
|
||||
// of the image shader will make it easier to handle these cases
|
||||
// properly.
|
||||
if (noHorizontalBorders || noVerticalBorders) {
|
||||
return ImgDrawResult::NOT_SUPPORTED;
|
||||
}
|
||||
|
@ -3704,8 +3707,11 @@ ImgDrawResult nsCSSBorderImageRenderer::CreateWebRenderCommands(
|
|||
LayoutDevicePoint lineStart;
|
||||
LayoutDevicePoint lineEnd;
|
||||
LayoutDeviceSize gradientRadius;
|
||||
LayoutDevicePoint gradientCenter;
|
||||
float gradientAngle;
|
||||
renderer.BuildWebRenderParameters(1.0, extendMode, stops, lineStart,
|
||||
lineEnd, gradientRadius);
|
||||
lineEnd, gradientRadius, gradientCenter,
|
||||
gradientAngle);
|
||||
|
||||
if (gradient.IsLinear()) {
|
||||
LayoutDevicePoint startPoint =
|
||||
|
@ -3723,7 +3729,7 @@ ImgDrawResult nsCSSBorderImageRenderer::CreateWebRenderCommands(
|
|||
extendMode,
|
||||
wr::ToLayoutSideOffsets(outset[0], outset[1], outset[2],
|
||||
outset[3]));
|
||||
} else {
|
||||
} else if (gradient.IsRadial()) {
|
||||
aBuilder.PushBorderRadialGradient(
|
||||
dest, clip, !aItem->BackfaceIsHidden(),
|
||||
wr::ToBorderWidths(widths[0], widths[1], widths[2], widths[3]),
|
||||
|
@ -3731,6 +3737,15 @@ ImgDrawResult nsCSSBorderImageRenderer::CreateWebRenderCommands(
|
|||
wr::ToLayoutSize(gradientRadius), stops, extendMode,
|
||||
wr::ToLayoutSideOffsets(outset[0], outset[1], outset[2],
|
||||
outset[3]));
|
||||
} else {
|
||||
MOZ_ASSERT(gradient.IsConic());
|
||||
aBuilder.PushBorderConicGradient(
|
||||
dest, clip, !aItem->BackfaceIsHidden(),
|
||||
wr::ToBorderWidths(widths[0], widths[1], widths[2], widths[3]),
|
||||
mFill, wr::ToLayoutPoint(gradientCenter), gradientAngle, stops,
|
||||
extendMode,
|
||||
wr::ToLayoutSideOffsets(outset[0], outset[1], outset[2],
|
||||
outset[3]));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -225,6 +225,17 @@ static Tuple<CSSPoint, CSSPoint, CSSCoord, CSSCoord> ComputeRadialGradientLine(
|
|||
return MakeTuple(start, end, radiusX, radiusY);
|
||||
}
|
||||
|
||||
// Compute the center and the start angle of the conic gradient.
|
||||
static Tuple<CSSPoint, float> ComputeConicGradientProperties(
|
||||
const StyleGradient& aGradient, const CSSSize& aBoxSize) {
|
||||
const auto& conic = aGradient.AsConic();
|
||||
const Position& position = conic.position;
|
||||
float angle = static_cast<float>(conic.angle.ToRadians());
|
||||
CSSPoint center = ResolvePosition(position, aBoxSize);
|
||||
|
||||
return MakeTuple(center, angle);
|
||||
}
|
||||
|
||||
static float Interpolate(float aF1, float aF2, float aFrac) {
|
||||
return aF1 + aFrac * (aF2 - aF1);
|
||||
}
|
||||
|
@ -563,22 +574,40 @@ static Maybe<double> GetSpecifiedGradientPosition(
|
|||
return Some(pos.ResolveToCSSPixels(aLineLength) / aLineLength);
|
||||
}
|
||||
|
||||
static nsTArray<ColorStop> ComputeColorStops(ComputedStyle* aComputedStyle,
|
||||
const StyleGradient& aGradient,
|
||||
// aLineLength argument is unused for conic-gradients.
|
||||
static Maybe<double> GetSpecifiedGradientPosition(
|
||||
const StyleGenericGradientItem<StyleColor, StyleAngleOrPercentage>& aItem,
|
||||
CSSCoord aLineLength) {
|
||||
auto items = aGradient.IsLinear() ? aGradient.AsLinear().items.AsSpan()
|
||||
: aGradient.AsRadial().items.AsSpan();
|
||||
if (aItem.IsSimpleColorStop()) {
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(items.Length() >= 2,
|
||||
const StyleAngleOrPercentage& pos = aItem.IsComplexColorStop()
|
||||
? aItem.AsComplexColorStop().position
|
||||
: aItem.AsInterpolationHint();
|
||||
|
||||
if (pos.IsPercentage()) {
|
||||
return Some(pos.AsPercentage()._0);
|
||||
}
|
||||
|
||||
return Some(pos.AsAngle().ToRadians() / (2 * M_PI));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static nsTArray<ColorStop> ComputeColorStopsForItems(
|
||||
ComputedStyle* aComputedStyle,
|
||||
Span<const StyleGenericGradientItem<StyleColor, T>> aItems,
|
||||
CSSCoord aLineLength) {
|
||||
MOZ_ASSERT(aItems.Length() >= 2,
|
||||
"The parser should reject gradients with less than two stops");
|
||||
|
||||
nsTArray<ColorStop> stops(items.Length());
|
||||
nsTArray<ColorStop> stops(aItems.Length());
|
||||
|
||||
// If there is a run of stops before stop i that did not have specified
|
||||
// positions, then this is the index of the first stop in that run.
|
||||
Maybe<size_t> firstUnsetPosition;
|
||||
for (size_t i = 0; i < items.Length(); ++i) {
|
||||
const auto& stop = items[i];
|
||||
for (size_t i = 0; i < aItems.Length(); ++i) {
|
||||
const auto& stop = aItems[i];
|
||||
double position;
|
||||
|
||||
Maybe<double> specifiedPosition =
|
||||
|
@ -589,7 +618,7 @@ static nsTArray<ColorStop> ComputeColorStops(ComputedStyle* aComputedStyle,
|
|||
} else if (i == 0) {
|
||||
// First stop defaults to position 0.0
|
||||
position = 0.0;
|
||||
} else if (i == items.Length() - 1) {
|
||||
} else if (i == aItems.Length() - 1) {
|
||||
// Last stop defaults to position 1.0
|
||||
position = 1.0;
|
||||
} else {
|
||||
|
@ -634,6 +663,21 @@ static nsTArray<ColorStop> ComputeColorStops(ComputedStyle* aComputedStyle,
|
|||
return stops;
|
||||
}
|
||||
|
||||
static nsTArray<ColorStop> ComputeColorStops(ComputedStyle* aComputedStyle,
|
||||
const StyleGradient& aGradient,
|
||||
CSSCoord aLineLength) {
|
||||
if (aGradient.IsLinear()) {
|
||||
return ComputeColorStopsForItems(
|
||||
aComputedStyle, aGradient.AsLinear().items.AsSpan(), aLineLength);
|
||||
}
|
||||
if (aGradient.IsRadial()) {
|
||||
return ComputeColorStopsForItems(
|
||||
aComputedStyle, aGradient.AsRadial().items.AsSpan(), aLineLength);
|
||||
}
|
||||
return ComputeColorStopsForItems(
|
||||
aComputedStyle, aGradient.AsConic().items.AsSpan(), aLineLength);
|
||||
}
|
||||
|
||||
nsCSSGradientRenderer nsCSSGradientRenderer::Create(
|
||||
nsPresContext* aPresContext, ComputedStyle* aComputedStyle,
|
||||
const StyleGradient& aGradient, const nsSize& aIntrinsicSize) {
|
||||
|
@ -641,19 +685,26 @@ nsCSSGradientRenderer nsCSSGradientRenderer::Create(
|
|||
|
||||
// Compute "gradient line" start and end relative to the intrinsic size of
|
||||
// the gradient.
|
||||
CSSPoint lineStart, lineEnd;
|
||||
CSSPoint lineStart, lineEnd, center; // center is for conic gradients only
|
||||
CSSCoord radiusX = 0, radiusY = 0; // for radial gradients only
|
||||
float angle = 0.0; // for conic gradients only
|
||||
if (aGradient.IsLinear()) {
|
||||
Tie(lineStart, lineEnd) =
|
||||
ComputeLinearGradientLine(aPresContext, aGradient, srcSize);
|
||||
} else {
|
||||
} else if (aGradient.IsRadial()) {
|
||||
Tie(lineStart, lineEnd, radiusX, radiusY) =
|
||||
ComputeRadialGradientLine(aGradient, srcSize);
|
||||
} else {
|
||||
MOZ_ASSERT(aGradient.IsConic());
|
||||
Tie(center, angle) = ComputeConicGradientProperties(aGradient, srcSize);
|
||||
}
|
||||
// Avoid sending Infs or Nans to downwind draw targets.
|
||||
if (!lineStart.IsFinite() || !lineEnd.IsFinite()) {
|
||||
lineStart = lineEnd = CSSPoint(0, 0);
|
||||
}
|
||||
if (!center.IsFinite()) {
|
||||
center = CSSPoint(0, 0);
|
||||
}
|
||||
CSSCoord lineLength =
|
||||
NS_hypot(lineEnd.x - lineStart.x, lineEnd.y - lineStart.y);
|
||||
|
||||
|
@ -677,6 +728,11 @@ nsCSSGradientRenderer nsCSSGradientRenderer::Create(
|
|||
};
|
||||
renderer.mRadiusX = aPresContext->CSSPixelsToDevPixels(radiusX);
|
||||
renderer.mRadiusY = aPresContext->CSSPixelsToDevPixels(radiusY);
|
||||
renderer.mCenter = {
|
||||
aPresContext->CSSPixelsToDevPixels(center.x),
|
||||
aPresContext->CSSPixelsToDevPixels(center.y),
|
||||
};
|
||||
renderer.mAngle = angle;
|
||||
return renderer;
|
||||
}
|
||||
|
||||
|
@ -869,8 +925,7 @@ void nsCSSGradientRenderer::Paint(gfxContext& aContext, const nsRect& aDest,
|
|||
|
||||
gradientPattern = new gfxPattern(gradientStart.x, gradientStart.y,
|
||||
gradientEnd.x, gradientEnd.y);
|
||||
} else {
|
||||
MOZ_ASSERT(mGradient->IsRadial());
|
||||
} else if (mGradient->IsRadial()) {
|
||||
NS_ASSERTION(firstStop >= 0.0,
|
||||
"Negative stops not allowed for radial gradients");
|
||||
|
||||
|
@ -895,6 +950,9 @@ void nsCSSGradientRenderer::Paint(gfxContext& aContext, const nsRect& aDest,
|
|||
matrix.PreScale(1.0, mRadiusX / mRadiusY);
|
||||
matrix.PreTranslate(-mLineStart);
|
||||
}
|
||||
} else {
|
||||
// conic-gradient is only implemented for WebRender
|
||||
return;
|
||||
}
|
||||
// Use a pattern transform to take account of source and dest rects
|
||||
matrix.PreTranslate(gfxPoint(mPresContext->CSSPixelsToDevPixels(aSrc.x),
|
||||
|
@ -1120,7 +1178,8 @@ bool nsCSSGradientRenderer::TryPaintTilesWithExtendMode(
|
|||
void nsCSSGradientRenderer::BuildWebRenderParameters(
|
||||
float aOpacity, wr::ExtendMode& aMode, nsTArray<wr::GradientStop>& aStops,
|
||||
LayoutDevicePoint& aLineStart, LayoutDevicePoint& aLineEnd,
|
||||
LayoutDeviceSize& aGradientRadius) {
|
||||
LayoutDeviceSize& aGradientRadius, LayoutDevicePoint& aGradientCenter,
|
||||
float& aGradientAngle) {
|
||||
aMode =
|
||||
mGradient->Repeating() ? wr::ExtendMode::Repeat : wr::ExtendMode::Clamp;
|
||||
|
||||
|
@ -1136,6 +1195,8 @@ void nsCSSGradientRenderer::BuildWebRenderParameters(
|
|||
aLineStart = LayoutDevicePoint(mLineStart.x, mLineStart.y);
|
||||
aLineEnd = LayoutDevicePoint(mLineEnd.x, mLineEnd.y);
|
||||
aGradientRadius = LayoutDeviceSize(mRadiusX, mRadiusY);
|
||||
aGradientCenter = LayoutDevicePoint(mCenter.x, mCenter.y);
|
||||
aGradientAngle = mAngle;
|
||||
}
|
||||
|
||||
void nsCSSGradientRenderer::BuildWebRenderDisplayItems(
|
||||
|
@ -1151,8 +1212,10 @@ void nsCSSGradientRenderer::BuildWebRenderDisplayItems(
|
|||
LayoutDevicePoint lineStart;
|
||||
LayoutDevicePoint lineEnd;
|
||||
LayoutDeviceSize gradientRadius;
|
||||
LayoutDevicePoint gradientCenter;
|
||||
float gradientAngle;
|
||||
BuildWebRenderParameters(aOpacity, extendMode, stops, lineStart, lineEnd,
|
||||
gradientRadius);
|
||||
gradientRadius, gradientCenter, gradientAngle);
|
||||
|
||||
nscoord appUnitsPerDevPixel = mPresContext->AppUnitsPerDevPixel();
|
||||
|
||||
|
@ -1188,6 +1251,9 @@ void nsCSSGradientRenderer::BuildWebRenderDisplayItems(
|
|||
lineStart.x = (lineStart.x - srcTransform.x) * srcTransform.width;
|
||||
lineStart.y = (lineStart.y - srcTransform.y) * srcTransform.height;
|
||||
|
||||
gradientCenter.x = (gradientCenter.x - srcTransform.x) * srcTransform.width;
|
||||
gradientCenter.y = (gradientCenter.y - srcTransform.y) * srcTransform.height;
|
||||
|
||||
if (mGradient->IsLinear()) {
|
||||
lineEnd.x = (lineEnd.x - srcTransform.x) * srcTransform.width;
|
||||
lineEnd.y = (lineEnd.y - srcTransform.y) * srcTransform.height;
|
||||
|
@ -1199,8 +1265,7 @@ void nsCSSGradientRenderer::BuildWebRenderDisplayItems(
|
|||
mozilla::wr::ToLayoutPoint(lineEnd), stops, extendMode,
|
||||
mozilla::wr::ToLayoutSize(firstTileBounds.Size()),
|
||||
mozilla::wr::ToLayoutSize(tileSpacing));
|
||||
} else {
|
||||
MOZ_ASSERT(mGradient->IsRadial());
|
||||
} else if (mGradient->IsRadial()) {
|
||||
gradientRadius.width *= srcTransform.width;
|
||||
gradientRadius.height *= srcTransform.height;
|
||||
|
||||
|
@ -1211,6 +1276,14 @@ void nsCSSGradientRenderer::BuildWebRenderDisplayItems(
|
|||
mozilla::wr::ToLayoutSize(gradientRadius), stops, extendMode,
|
||||
mozilla::wr::ToLayoutSize(firstTileBounds.Size()),
|
||||
mozilla::wr::ToLayoutSize(tileSpacing));
|
||||
} else {
|
||||
MOZ_ASSERT(mGradient->IsConic());
|
||||
aBuilder.PushConicGradient(
|
||||
mozilla::wr::ToLayoutRect(gradientBounds),
|
||||
mozilla::wr::ToLayoutRect(clipBounds), aIsBackfaceVisible,
|
||||
mozilla::wr::ToLayoutPoint(gradientCenter), gradientAngle, stops,
|
||||
extendMode, mozilla::wr::ToLayoutSize(firstTileBounds.Size()),
|
||||
mozilla::wr::ToLayoutSize(tileSpacing));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -65,7 +65,9 @@ class nsCSSGradientRenderer final {
|
|||
nsTArray<wr::GradientStop>& aStops,
|
||||
LayoutDevicePoint& aLineStart,
|
||||
LayoutDevicePoint& aLineEnd,
|
||||
LayoutDeviceSize& aGradientRadius);
|
||||
LayoutDeviceSize& aGradientRadius,
|
||||
LayoutDevicePoint& aGradientCenter,
|
||||
float& aGradientAngle);
|
||||
|
||||
/**
|
||||
* Build display items for the gradient
|
||||
|
@ -89,7 +91,8 @@ class nsCSSGradientRenderer final {
|
|||
: mPresContext(nullptr),
|
||||
mGradient(nullptr),
|
||||
mRadiusX(0.0),
|
||||
mRadiusY(0.0) {}
|
||||
mRadiusY(0.0),
|
||||
mAngle(0.0) {}
|
||||
|
||||
/**
|
||||
* Attempts to paint the tiles for a gradient by painting it once to an
|
||||
|
@ -107,8 +110,10 @@ class nsCSSGradientRenderer final {
|
|||
nsPresContext* mPresContext;
|
||||
const StyleGradient* mGradient;
|
||||
nsTArray<ColorStop> mStops;
|
||||
gfxPoint mLineStart, mLineEnd;
|
||||
double mRadiusX, mRadiusY;
|
||||
gfxPoint mLineStart, mLineEnd; // only for linear/radial gradients
|
||||
double mRadiusX, mRadiusY; // only for radial gradients
|
||||
gfxPoint mCenter; // only for conic gradients
|
||||
float mAngle; // only for conic gradients
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -441,7 +441,13 @@ inline imgRequestProxy* StyleComputedImageUrl::GetImage() const {
|
|||
|
||||
template <>
|
||||
inline bool StyleGradient::Repeating() const {
|
||||
return IsLinear() ? AsLinear().repeating : AsRadial().repeating;
|
||||
if (IsLinear()) {
|
||||
return AsLinear().repeating;
|
||||
}
|
||||
if (IsRadial()) {
|
||||
return AsRadial().repeating;
|
||||
}
|
||||
return AsConic().repeating;
|
||||
}
|
||||
|
||||
template <>
|
||||
|
|
|
@ -1402,11 +1402,10 @@ nsChangeHint nsStyleTableBorder::CalcDifference(
|
|||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
bool StyleGradient::IsOpaque() const {
|
||||
auto items =
|
||||
IsLinear() ? AsLinear().items.AsSpan() : AsRadial().items.AsSpan();
|
||||
for (auto& stop : items) {
|
||||
template <typename T>
|
||||
static bool GradientItemsAreOpaque(
|
||||
Span<const StyleGenericGradientItem<StyleColor, T>> aItems) {
|
||||
for (auto& stop : aItems) {
|
||||
if (stop.IsInterpolationHint()) {
|
||||
continue;
|
||||
}
|
||||
|
@ -1423,6 +1422,17 @@ bool StyleGradient::IsOpaque() const {
|
|||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool StyleGradient::IsOpaque() const {
|
||||
if (IsLinear()) {
|
||||
return GradientItemsAreOpaque(AsLinear().items.AsSpan());
|
||||
}
|
||||
if (IsRadial()) {
|
||||
return GradientItemsAreOpaque(AsRadial().items.AsSpan());
|
||||
}
|
||||
return GradientItemsAreOpaque(AsConic().items.AsSpan());
|
||||
}
|
||||
|
||||
// --------------------
|
||||
// CachedBorderImageData
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче