mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
Bug 1615489 - Refactor GenericGradient for conic-gradient support. r=emilio
Differential Revision: https://phabricator.services.mozilla.com/D62923 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
6d9fd9419f
commit
c15714cbeb
@ -3707,7 +3707,7 @@ ImgDrawResult nsCSSBorderImageRenderer::CreateWebRenderCommands(
|
||||
renderer.BuildWebRenderParameters(1.0, extendMode, stops, lineStart,
|
||||
lineEnd, gradientRadius);
|
||||
|
||||
if (gradient.kind.IsLinear()) {
|
||||
if (gradient.IsLinear()) {
|
||||
LayoutDevicePoint startPoint =
|
||||
LayoutDevicePoint(dest.origin.x, dest.origin.y) + lineStart;
|
||||
LayoutDevicePoint endPoint =
|
||||
|
@ -66,9 +66,9 @@ static Tuple<CSSPoint, CSSPoint> ComputeLinearGradientLine(
|
||||
using X = StyleHorizontalPositionKeyword;
|
||||
using Y = StyleVerticalPositionKeyword;
|
||||
|
||||
const StyleLineDirection& direction = aGradient.kind.AsLinear();
|
||||
const StyleLineDirection& direction = aGradient.AsLinear().direction;
|
||||
const bool isModern =
|
||||
aGradient.compat_mode == StyleGradientCompatMode::Modern;
|
||||
aGradient.AsLinear().compat_mode == StyleGradientCompatMode::Modern;
|
||||
|
||||
CSSPoint center(aBoxSize.width / 2, aBoxSize.height / 2);
|
||||
switch (direction.tag) {
|
||||
@ -154,9 +154,9 @@ static RadialGradientRadii ComputeRadialGradientRadii(const EndingShape& aShape,
|
||||
// ellipse to use.
|
||||
static Tuple<CSSPoint, CSSPoint, CSSCoord, CSSCoord> ComputeRadialGradientLine(
|
||||
const StyleGradient& aGradient, const CSSSize& aBoxSize) {
|
||||
const auto& radial = aGradient.kind.AsRadial();
|
||||
const EndingShape& endingShape = radial._0;
|
||||
const Position& position = radial._1;
|
||||
const auto& radial = aGradient.AsRadial();
|
||||
const EndingShape& endingShape = radial.shape;
|
||||
const Position& position = radial.position;
|
||||
CSSPoint start = ResolvePosition(position, aBoxSize);
|
||||
|
||||
// Compute gradient shape: the x and y radii of an ellipse.
|
||||
@ -566,17 +566,19 @@ static Maybe<double> GetSpecifiedGradientPosition(
|
||||
static nsTArray<ColorStop> ComputeColorStops(ComputedStyle* aComputedStyle,
|
||||
const StyleGradient& aGradient,
|
||||
CSSCoord aLineLength) {
|
||||
MOZ_ASSERT(aGradient.items.Length() >= 2,
|
||||
auto items = aGradient.IsLinear() ? aGradient.AsLinear().items.AsSpan()
|
||||
: aGradient.AsRadial().items.AsSpan();
|
||||
|
||||
MOZ_ASSERT(items.Length() >= 2,
|
||||
"The parser should reject gradients with less than two stops");
|
||||
|
||||
nsTArray<ColorStop> stops(aGradient.items.Length());
|
||||
nsTArray<ColorStop> stops(items.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;
|
||||
auto span = aGradient.items.AsSpan();
|
||||
for (size_t i = 0; i < aGradient.items.Length(); ++i) {
|
||||
const auto& stop = span[i];
|
||||
for (size_t i = 0; i < items.Length(); ++i) {
|
||||
const auto& stop = items[i];
|
||||
double position;
|
||||
|
||||
Maybe<double> specifiedPosition =
|
||||
@ -587,7 +589,7 @@ static nsTArray<ColorStop> ComputeColorStops(ComputedStyle* aComputedStyle,
|
||||
} else if (i == 0) {
|
||||
// First stop defaults to position 0.0
|
||||
position = 0.0;
|
||||
} else if (i == aGradient.items.Length() - 1) {
|
||||
} else if (i == items.Length() - 1) {
|
||||
// Last stop defaults to position 1.0
|
||||
position = 1.0;
|
||||
} else {
|
||||
@ -641,7 +643,7 @@ nsCSSGradientRenderer nsCSSGradientRenderer::Create(
|
||||
// the gradient.
|
||||
CSSPoint lineStart, lineEnd;
|
||||
CSSCoord radiusX = 0, radiusY = 0; // for radial gradients only
|
||||
if (aGradient.kind.IsLinear()) {
|
||||
if (aGradient.IsLinear()) {
|
||||
Tie(lineStart, lineEnd) =
|
||||
ComputeLinearGradientLine(aPresContext, aGradient, srcSize);
|
||||
} else {
|
||||
@ -699,10 +701,10 @@ void nsCSSGradientRenderer::Paint(gfxContext& aContext, const nsRect& aDest,
|
||||
// between tiles, we can optimise away most of the work by converting to a
|
||||
// repeating linear gradient and filling the whole destination rect at once.
|
||||
bool forceRepeatToCoverTiles =
|
||||
mGradient->kind.IsLinear() &&
|
||||
mGradient->IsLinear() &&
|
||||
(mLineStart.x == mLineEnd.x) != (mLineStart.y == mLineEnd.y) &&
|
||||
aRepeatSize.width == aDest.width && aRepeatSize.height == aDest.height &&
|
||||
!mGradient->repeating && !aSrc.IsEmpty() && !cellContainsFill;
|
||||
!mGradient->AsLinear().repeating && !aSrc.IsEmpty() && !cellContainsFill;
|
||||
|
||||
gfxMatrix matrix;
|
||||
if (forceRepeatToCoverTiles) {
|
||||
@ -751,8 +753,8 @@ void nsCSSGradientRenderer::Paint(gfxContext& aContext, const nsRect& aDest,
|
||||
|
||||
// Eliminate negative-position stops if the gradient is radial.
|
||||
double firstStop = mStops[0].mPosition;
|
||||
if (!mGradient->kind.IsLinear() && firstStop < 0.0) {
|
||||
if (mGradient->repeating) {
|
||||
if (mGradient->IsRadial() && firstStop < 0.0) {
|
||||
if (mGradient->AsRadial().repeating) {
|
||||
// Choose an instance of the repeated pattern that gives us all positive
|
||||
// stop-offsets.
|
||||
double lastStop = mStops[mStops.Length() - 1].mPosition;
|
||||
@ -805,7 +807,7 @@ void nsCSSGradientRenderer::Paint(gfxContext& aContext, const nsRect& aDest,
|
||||
MOZ_ASSERT(firstStop >= 0.0, "Failed to fix stop offsets");
|
||||
}
|
||||
|
||||
if (!mGradient->kind.IsLinear() && !mGradient->repeating) {
|
||||
if (mGradient->IsRadial() && !mGradient->AsRadial().repeating) {
|
||||
// Direct2D can only handle a particular class of radial gradients because
|
||||
// of the way the it specifies gradients. Setting firstStop to 0, when we
|
||||
// can, will help us stay on the fast path. Currently we don't do this
|
||||
@ -823,13 +825,13 @@ void nsCSSGradientRenderer::Paint(gfxContext& aContext, const nsRect& aDest,
|
||||
double stopEnd = lastStop;
|
||||
double stopDelta = lastStop - firstStop;
|
||||
bool zeroRadius =
|
||||
!mGradient->kind.IsLinear() && (mRadiusX < 1e-6 || mRadiusY < 1e-6);
|
||||
mGradient->IsRadial() && (mRadiusX < 1e-6 || mRadiusY < 1e-6);
|
||||
if (stopDelta < 1e-6 || lineLength < 1e-6 || zeroRadius) {
|
||||
// Stops are all at the same place. Map all stops to 0.0.
|
||||
// For repeating radial gradients, or for any radial gradients with
|
||||
// a zero radius, we need to fill with the last stop color, so just set
|
||||
// both radii to 0.
|
||||
if (mGradient->repeating || zeroRadius) {
|
||||
if (mGradient->Repeating() || zeroRadius) {
|
||||
mRadiusX = mRadiusY = 0.0;
|
||||
}
|
||||
stopDelta = 0.0;
|
||||
@ -839,7 +841,7 @@ void nsCSSGradientRenderer::Paint(gfxContext& aContext, const nsRect& aDest,
|
||||
// This keeps the gradient line as large as the box and doesn't
|
||||
// lets us avoiding having to get padding correct for stops
|
||||
// at 0 and 1
|
||||
if (!mGradient->repeating || stopDelta == 0.0) {
|
||||
if (!mGradient->Repeating() || stopDelta == 0.0) {
|
||||
stopOrigin = std::min(stopOrigin, 0.0);
|
||||
stopEnd = std::max(stopEnd, 1.0);
|
||||
}
|
||||
@ -849,7 +851,7 @@ void nsCSSGradientRenderer::Paint(gfxContext& aContext, const nsRect& aDest,
|
||||
RefPtr<gfxPattern> gradientPattern;
|
||||
gfxPoint gradientStart;
|
||||
gfxPoint gradientEnd;
|
||||
if (mGradient->kind.IsLinear()) {
|
||||
if (mGradient->IsLinear()) {
|
||||
// Compute the actual gradient line ends we need to pass to cairo after
|
||||
// stops have been normalized.
|
||||
gradientStart = mLineStart + (mLineEnd - mLineStart) * stopOrigin;
|
||||
@ -868,6 +870,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());
|
||||
NS_ASSERTION(firstStop >= 0.0,
|
||||
"Negative stops not allowed for radial gradients");
|
||||
|
||||
@ -912,7 +915,7 @@ void nsCSSGradientRenderer::Paint(gfxContext& aContext, const nsRect& aDest,
|
||||
Color lastColor(mStops.LastElement().mColor);
|
||||
mStops.Clear();
|
||||
|
||||
if (!mGradient->repeating && !zeroRadius) {
|
||||
if (!mGradient->Repeating() && !zeroRadius) {
|
||||
mStops.AppendElement(ColorStop(firstStop, false, firstColor));
|
||||
}
|
||||
mStops.AppendElement(ColorStop(firstStop, false, lastColor));
|
||||
@ -920,7 +923,7 @@ void nsCSSGradientRenderer::Paint(gfxContext& aContext, const nsRect& aDest,
|
||||
|
||||
ResolvePremultipliedAlpha(mStops);
|
||||
|
||||
bool isRepeat = mGradient->repeating || forceRepeatToCoverTiles;
|
||||
bool isRepeat = mGradient->Repeating() || forceRepeatToCoverTiles;
|
||||
|
||||
// Now set normalized color stops in pattern.
|
||||
// Offscreen gradient surface cache (not a tile):
|
||||
@ -1014,7 +1017,7 @@ void nsCSSGradientRenderer::Paint(gfxContext& aContext, const nsRect& aDest,
|
||||
gfxRect dirtyFillRect = fillRect.Intersect(dirtyAreaToFill);
|
||||
gfxRect fillRectRelativeToTile = dirtyFillRect - tileRect.TopLeft();
|
||||
Color edgeColor;
|
||||
if (mGradient->kind.IsLinear() && !isRepeat &&
|
||||
if (mGradient->IsLinear() && !isRepeat &&
|
||||
RectIsBeyondLinearGradientEdge(fillRectRelativeToTile, matrix, mStops,
|
||||
gradientStart, gradientEnd,
|
||||
&edgeColor)) {
|
||||
@ -1118,7 +1121,8 @@ void nsCSSGradientRenderer::BuildWebRenderParameters(
|
||||
float aOpacity, wr::ExtendMode& aMode, nsTArray<wr::GradientStop>& aStops,
|
||||
LayoutDevicePoint& aLineStart, LayoutDevicePoint& aLineEnd,
|
||||
LayoutDeviceSize& aGradientRadius) {
|
||||
aMode = mGradient->repeating ? wr::ExtendMode::Repeat : wr::ExtendMode::Clamp;
|
||||
aMode =
|
||||
mGradient->Repeating() ? wr::ExtendMode::Repeat : wr::ExtendMode::Clamp;
|
||||
|
||||
aStops.SetLength(mStops.Length());
|
||||
for (uint32_t i = 0; i < mStops.Length(); i++) {
|
||||
@ -1184,7 +1188,7 @@ void nsCSSGradientRenderer::BuildWebRenderDisplayItems(
|
||||
lineStart.x = (lineStart.x - srcTransform.x) * srcTransform.width;
|
||||
lineStart.y = (lineStart.y - srcTransform.y) * srcTransform.height;
|
||||
|
||||
if (mGradient->kind.IsLinear()) {
|
||||
if (mGradient->IsLinear()) {
|
||||
lineEnd.x = (lineEnd.x - srcTransform.x) * srcTransform.width;
|
||||
lineEnd.y = (lineEnd.y - srcTransform.y) * srcTransform.height;
|
||||
|
||||
@ -1196,6 +1200,7 @@ void nsCSSGradientRenderer::BuildWebRenderDisplayItems(
|
||||
mozilla::wr::ToLayoutSize(firstTileBounds.Size()),
|
||||
mozilla::wr::ToLayoutSize(tileSpacing));
|
||||
} else {
|
||||
MOZ_ASSERT(mGradient->IsRadial());
|
||||
gradientRadius.width *= srcTransform.width;
|
||||
gradientRadius.height *= srcTransform.height;
|
||||
|
||||
|
@ -439,6 +439,11 @@ inline imgRequestProxy* StyleComputedImageUrl::GetImage() const {
|
||||
return LoadData().resolved_image;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool StyleGradient::Repeating() const {
|
||||
return IsLinear() ? AsLinear().repeating : AsRadial().repeating;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool StyleGradient::IsOpaque() const;
|
||||
|
||||
|
@ -1404,7 +1404,9 @@ nsChangeHint nsStyleTableBorder::CalcDifference(
|
||||
|
||||
template <>
|
||||
bool StyleGradient::IsOpaque() const {
|
||||
for (auto& stop : items.AsSpan()) {
|
||||
auto items =
|
||||
IsLinear() ? AsLinear().items.AsSpan() : AsRadial().items.AsSpan();
|
||||
for (auto& stop : items) {
|
||||
if (stop.IsInterpolationHint()) {
|
||||
continue;
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ pub use self::GenericImage as Image;
|
||||
/// <https://drafts.csswg.org/css-images/#gradients>
|
||||
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)]
|
||||
#[repr(C)]
|
||||
pub struct GenericGradient<
|
||||
pub enum GenericGradient<
|
||||
LineDirection,
|
||||
LengthPercentage,
|
||||
NonNegativeLength,
|
||||
@ -59,19 +59,30 @@ pub struct GenericGradient<
|
||||
Position,
|
||||
Color,
|
||||
> {
|
||||
/// Gradients can be linear or radial.
|
||||
pub kind: GenericGradientKind<
|
||||
LineDirection,
|
||||
NonNegativeLength,
|
||||
NonNegativeLengthPercentage,
|
||||
Position,
|
||||
>,
|
||||
/// The color stops and interpolation hints.
|
||||
pub items: crate::OwnedSlice<GenericGradientItem<Color, LengthPercentage>>,
|
||||
/// True if this is a repeating gradient.
|
||||
pub repeating: bool,
|
||||
/// Compatibility mode.
|
||||
pub compat_mode: GradientCompatMode,
|
||||
/// A linear gradient.
|
||||
Linear {
|
||||
/// Line direction
|
||||
direction: LineDirection,
|
||||
/// The color stops and interpolation hints.
|
||||
items: crate::OwnedSlice<GenericGradientItem<Color, LengthPercentage>>,
|
||||
/// True if this is a repeating gradient.
|
||||
repeating: bool,
|
||||
/// Compatibility mode.
|
||||
compat_mode: GradientCompatMode,
|
||||
},
|
||||
/// A radial gradient.
|
||||
Radial {
|
||||
/// Shape of gradient
|
||||
shape: GenericEndingShape<NonNegativeLength, NonNegativeLengthPercentage>,
|
||||
/// Center of gradient
|
||||
position: Position,
|
||||
/// The color stops and interpolation hints.
|
||||
items: crate::OwnedSlice<GenericGradientItem<Color, LengthPercentage>>,
|
||||
/// True if this is a repeating gradient.
|
||||
repeating: bool,
|
||||
/// Compatibility mode.
|
||||
compat_mode: GradientCompatMode,
|
||||
},
|
||||
}
|
||||
|
||||
pub use self::GenericGradient as Gradient;
|
||||
@ -88,26 +99,6 @@ pub enum GradientCompatMode {
|
||||
Moz,
|
||||
}
|
||||
|
||||
/// A gradient kind.
|
||||
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)]
|
||||
#[repr(C, u8)]
|
||||
pub enum GenericGradientKind<
|
||||
LineDirection,
|
||||
NonNegativeLength,
|
||||
NonNegativeLengthPercentage,
|
||||
Position,
|
||||
> {
|
||||
/// A linear gradient.
|
||||
Linear(LineDirection),
|
||||
/// A radial gradient.
|
||||
Radial(
|
||||
GenericEndingShape<NonNegativeLength, NonNegativeLengthPercentage>,
|
||||
Position,
|
||||
),
|
||||
}
|
||||
|
||||
pub use self::GenericGradientKind as GradientKind;
|
||||
|
||||
/// A radial gradient's ending shape.
|
||||
#[derive(
|
||||
Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem,
|
||||
@ -330,32 +321,39 @@ where
|
||||
where
|
||||
W: Write,
|
||||
{
|
||||
match self.compat_mode {
|
||||
let (compat_mode, repeating) = match *self {
|
||||
Gradient::Linear { compat_mode, repeating, .. } => (compat_mode, repeating),
|
||||
Gradient::Radial { compat_mode, repeating, .. } => (compat_mode, repeating),
|
||||
};
|
||||
|
||||
match compat_mode {
|
||||
GradientCompatMode::WebKit => dest.write_str("-webkit-")?,
|
||||
GradientCompatMode::Moz => dest.write_str("-moz-")?,
|
||||
_ => {},
|
||||
}
|
||||
|
||||
if self.repeating {
|
||||
if repeating {
|
||||
dest.write_str("repeating-")?;
|
||||
}
|
||||
dest.write_str(self.kind.label())?;
|
||||
dest.write_str("-gradient(")?;
|
||||
let mut skip_comma = match self.kind {
|
||||
GradientKind::Linear(ref direction) if direction.points_downwards(self.compat_mode) => {
|
||||
true
|
||||
|
||||
let (items, mut skip_comma) = match *self {
|
||||
Gradient::Linear { ref direction, compat_mode, ref items, .. } => {
|
||||
dest.write_str("linear-gradient(")?;
|
||||
if !direction.points_downwards(compat_mode) {
|
||||
direction.to_css(dest, compat_mode)?;
|
||||
(items, false)
|
||||
} else {
|
||||
(items, true)
|
||||
}
|
||||
},
|
||||
GradientKind::Linear(ref direction) => {
|
||||
direction.to_css(dest, self.compat_mode)?;
|
||||
false
|
||||
},
|
||||
GradientKind::Radial(ref shape, ref position) => {
|
||||
Gradient::Radial { ref shape, ref position, compat_mode, ref items, .. } => {
|
||||
dest.write_str("radial-gradient(")?;
|
||||
let omit_shape = match *shape {
|
||||
EndingShape::Ellipse(Ellipse::Extent(ShapeExtent::Cover)) |
|
||||
EndingShape::Ellipse(Ellipse::Extent(ShapeExtent::FarthestCorner)) => true,
|
||||
_ => false,
|
||||
};
|
||||
if self.compat_mode == GradientCompatMode::Modern {
|
||||
if compat_mode == GradientCompatMode::Modern {
|
||||
if !omit_shape {
|
||||
shape.to_css(dest)?;
|
||||
dest.write_str(" ")?;
|
||||
@ -369,10 +367,10 @@ where
|
||||
shape.to_css(dest)?;
|
||||
}
|
||||
}
|
||||
false
|
||||
(items, false)
|
||||
},
|
||||
};
|
||||
for item in &*self.items {
|
||||
for item in &**items {
|
||||
if !skip_comma {
|
||||
dest.write_str(", ")?;
|
||||
}
|
||||
@ -383,15 +381,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<D, L, LoP, P> GradientKind<D, L, LoP, P> {
|
||||
fn label(&self) -> &str {
|
||||
match *self {
|
||||
GradientKind::Linear(..) => "linear",
|
||||
GradientKind::Radial(..) => "radial",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The direction of a linear gradient.
|
||||
pub trait LineDirection {
|
||||
/// Whether this direction points towards, and thus can be omitted.
|
||||
|
@ -70,10 +70,6 @@ impl SpecifiedValueInfo for Gradient {
|
||||
}
|
||||
}
|
||||
|
||||
/// A specified gradient kind.
|
||||
pub type GradientKind =
|
||||
generic::GradientKind<LineDirection, NonNegativeLength, NonNegativeLengthPercentage, Position>;
|
||||
|
||||
/// A specified gradient line direction.
|
||||
///
|
||||
/// FIXME(emilio): This should be generic over Angle.
|
||||
@ -245,25 +241,12 @@ impl Parse for Gradient {
|
||||
}
|
||||
};
|
||||
|
||||
let (kind, items) = input.parse_nested_block(|i| {
|
||||
let shape = match shape {
|
||||
Shape::Linear => GradientKind::parse_linear(context, i, &mut compat_mode)?,
|
||||
Shape::Radial => GradientKind::parse_radial(context, i, &mut compat_mode)?,
|
||||
};
|
||||
let items = generic::GradientItem::parse_comma_separated(context, i)?;
|
||||
Ok((shape, items))
|
||||
})?;
|
||||
|
||||
if items.len() < 2 {
|
||||
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||
}
|
||||
|
||||
Ok(Gradient {
|
||||
items,
|
||||
repeating,
|
||||
kind,
|
||||
compat_mode,
|
||||
})
|
||||
Ok(input.parse_nested_block(|i| {
|
||||
Ok(match shape {
|
||||
Shape::Linear => Self::parse_linear(context, i, repeating, &mut compat_mode)?,
|
||||
Shape::Radial => Self::parse_radial(context, i, repeating, compat_mode)?,
|
||||
})
|
||||
})?)
|
||||
}
|
||||
}
|
||||
|
||||
@ -383,16 +366,21 @@ impl Gradient {
|
||||
let ident = input.expect_ident_cloned()?;
|
||||
input.expect_comma()?;
|
||||
|
||||
let (kind, reverse_stops) = match_ignore_ascii_case! { &ident,
|
||||
Ok(match_ignore_ascii_case! { &ident,
|
||||
"linear" => {
|
||||
let first = Point::parse(context, input)?;
|
||||
input.expect_comma()?;
|
||||
let second = Point::parse(context, input)?;
|
||||
|
||||
let direction = LineDirection::from_points(first, second);
|
||||
let kind = generic::GradientKind::Linear(direction);
|
||||
let items = Gradient::parse_webkit_gradient_stops(context, input, false)?;
|
||||
|
||||
(kind, false)
|
||||
generic::Gradient::Linear {
|
||||
direction,
|
||||
items,
|
||||
repeating: false,
|
||||
compat_mode: GradientCompatMode::Modern,
|
||||
}
|
||||
},
|
||||
"radial" => {
|
||||
let first_point = Point::parse(context, input)?;
|
||||
@ -412,16 +400,28 @@ impl Gradient {
|
||||
let rad = Circle::Radius(NonNegative(Length::from_px(radius.value)));
|
||||
let shape = generic::EndingShape::Circle(rad);
|
||||
let position: Position = point.into();
|
||||
let items = Gradient::parse_webkit_gradient_stops(context, input, reverse_stops)?;
|
||||
|
||||
let kind = generic::GradientKind::Radial(shape, position);
|
||||
(kind, reverse_stops)
|
||||
generic::Gradient::Radial {
|
||||
shape,
|
||||
position,
|
||||
items,
|
||||
repeating: false,
|
||||
compat_mode: GradientCompatMode::Modern,
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
let e = SelectorParseErrorKind::UnexpectedIdent(ident.clone());
|
||||
return Err(input.new_custom_error(e));
|
||||
},
|
||||
};
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_webkit_gradient_stops<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
reverse_stops: bool,
|
||||
) -> Result<crate::OwnedSlice<generic::GradientItem<Color, LengthPercentage>>, ParseError<'i>> {
|
||||
let mut items = input
|
||||
.try(|i| {
|
||||
i.expect_comma()?;
|
||||
@ -500,22 +500,29 @@ impl Gradient {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Ok(generic::Gradient {
|
||||
kind,
|
||||
items: items.into(),
|
||||
repeating: false,
|
||||
compat_mode: GradientCompatMode::Modern,
|
||||
})
|
||||
Ok(items.into())
|
||||
}
|
||||
|
||||
/// Not used for -webkit-gradient syntax.
|
||||
fn parse_stops<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<crate::OwnedSlice<generic::GradientItem<Color, LengthPercentage>>, ParseError<'i>> {
|
||||
let items = generic::GradientItem::parse_comma_separated(context, input)?;
|
||||
|
||||
if items.len() < 2 {
|
||||
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||
}
|
||||
|
||||
Ok(items)
|
||||
}
|
||||
}
|
||||
|
||||
impl GradientKind {
|
||||
/// Parses a linear gradient.
|
||||
/// GradientCompatMode can change during `-moz-` prefixed gradient parsing if it come across a `to` keyword.
|
||||
fn parse_linear<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
repeating: bool,
|
||||
compat_mode: &mut GradientCompatMode,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
let direction = if let Ok(d) = input.try(|i| LineDirection::parse(context, i, compat_mode))
|
||||
@ -523,23 +530,33 @@ impl GradientKind {
|
||||
input.expect_comma()?;
|
||||
d
|
||||
} else {
|
||||
match *compat_mode {
|
||||
match compat_mode {
|
||||
GradientCompatMode::Modern => {
|
||||
LineDirection::Vertical(VerticalPositionKeyword::Bottom)
|
||||
},
|
||||
_ => LineDirection::Vertical(VerticalPositionKeyword::Top),
|
||||
}
|
||||
};
|
||||
Ok(generic::GradientKind::Linear(direction))
|
||||
let items = Gradient::parse_stops(context, input)?;
|
||||
|
||||
Ok(Gradient::Linear {
|
||||
direction,
|
||||
items,
|
||||
repeating,
|
||||
compat_mode: *compat_mode,
|
||||
})
|
||||
}
|
||||
|
||||
/// Parses a radial gradient.
|
||||
fn parse_radial<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
compat_mode: &mut GradientCompatMode,
|
||||
repeating: bool,
|
||||
compat_mode: GradientCompatMode,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
let (shape, position) = match *compat_mode {
|
||||
let (shape, position) = match compat_mode {
|
||||
GradientCompatMode::Modern => {
|
||||
let shape = input.try(|i| EndingShape::parse(context, i, *compat_mode));
|
||||
let shape = input.try(|i| EndingShape::parse(context, i, compat_mode));
|
||||
let position = input.try(|i| {
|
||||
i.expect_ident_matching("at")?;
|
||||
Position::parse(context, i)
|
||||
@ -552,7 +569,7 @@ impl GradientKind {
|
||||
if position.is_ok() {
|
||||
i.expect_comma()?;
|
||||
}
|
||||
EndingShape::parse(context, i, *compat_mode)
|
||||
EndingShape::parse(context, i, compat_mode)
|
||||
});
|
||||
(shape, position.ok())
|
||||
},
|
||||
@ -567,7 +584,16 @@ impl GradientKind {
|
||||
});
|
||||
|
||||
let position = position.unwrap_or(Position::center());
|
||||
Ok(generic::GradientKind::Radial(shape, position))
|
||||
|
||||
let items = Gradient::parse_stops(context, input)?;
|
||||
|
||||
Ok(Gradient::Radial {
|
||||
shape,
|
||||
position,
|
||||
items,
|
||||
repeating,
|
||||
compat_mode,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ use style_traits::values::specified::AllowedNumericType;
|
||||
use style_traits::{ParseError, SpecifiedValueInfo, StyleParseErrorKind};
|
||||
|
||||
pub use super::image::{EndingShape as GradientEndingShape, Gradient};
|
||||
pub use super::image::{GradientKind, Image};
|
||||
pub use super::image::Image;
|
||||
pub use crate::values::specified::calc::CalcLengthPercentage;
|
||||
|
||||
/// Number of app units per pixel
|
||||
|
@ -56,7 +56,7 @@ pub use self::font::{FontVariantAlternates, FontWeight};
|
||||
pub use self::font::{FontVariantEastAsian, FontVariationSettings};
|
||||
pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextZoom};
|
||||
pub use self::image::{EndingShape as GradientEndingShape, Gradient};
|
||||
pub use self::image::{GradientKind, Image, MozImageRect};
|
||||
pub use self::image::{Image, MozImageRect};
|
||||
pub use self::length::{AbsoluteLength, CalcLengthPercentage, CharacterWidth};
|
||||
pub use self::length::{FontRelativeLength, Length, LengthOrNumber, NonNegativeLengthOrNumber};
|
||||
pub use self::length::{LengthOrAuto, LengthPercentage, LengthPercentageOrAuto};
|
||||
|
@ -671,6 +671,7 @@ renaming_overrides_prefixing = true
|
||||
"""
|
||||
|
||||
"GenericGradient" = """
|
||||
inline bool Repeating() const;
|
||||
bool IsOpaque() const;
|
||||
"""
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user