author | Anthony Ramine <n.oxyde@gmail.com> |
Thu, 20 Apr 2017 04:27:33 -0500 | |
changeset 354048 | 25944baae7b0b1c5f2bcaa3a4dda0287c6fa778c |
parent 354047 | e8babe547652de8cfb5aa274487151f848fab093 |
child 354049 | 66be5ce5eb0661ba4782c9de162cdf5cd45b54c6 |
push id | 31685 |
push user | kwierso@gmail.com |
push date | Thu, 20 Apr 2017 21:45:29 +0000 |
treeherder | mozilla-central@5e3dc7e1288a [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | emilio |
milestone | 55.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
|
servo/components/style/gecko/conversions.rs | file | annotate | diff | comparison | revisions | |
servo/components/style/values/specified/image.rs | file | annotate | diff | comparison | revisions |
--- a/servo/components/style/gecko/conversions.rs +++ b/servo/components/style/gecko/conversions.rs @@ -202,40 +202,40 @@ impl nsStyleImage { (*gecko_gradient).mBgPosY .set_value(CoordDataValue::Percent(percent_y)); } } } gecko_gradient }, GradientKind::Radial(shape, position) => { + let keyword_to_gecko_size = |keyword| { + match keyword { + SizeKeyword::ClosestSide => NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE, + SizeKeyword::FarthestSide => NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE, + SizeKeyword::ClosestCorner => NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER, + SizeKeyword::FarthestCorner => NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER, + SizeKeyword::Contain => NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE, + SizeKeyword::Cover => NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER, + } + }; let (gecko_shape, gecko_size) = match shape { GradientShape::Circle(ref length) => { let size = match *length { LengthOrKeyword::Keyword(keyword) => { - match keyword { - SizeKeyword::ClosestSide => NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE, - SizeKeyword::FarthestSide => NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE, - SizeKeyword::ClosestCorner => NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER, - SizeKeyword::FarthestCorner => NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER, - } + keyword_to_gecko_size(keyword) }, _ => NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE, }; (NS_STYLE_GRADIENT_SHAPE_CIRCULAR as u8, size as u8) }, GradientShape::Ellipse(ref length) => { let size = match *length { LengthOrPercentageOrKeyword::Keyword(keyword) => { - match keyword { - SizeKeyword::ClosestSide => NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE, - SizeKeyword::FarthestSide => NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE, - SizeKeyword::ClosestCorner => NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER, - SizeKeyword::FarthestCorner => NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER, - } + keyword_to_gecko_size(keyword) }, _ => NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE, }; (NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL as u8, size as u8) } }; let gecko_gradient = unsafe {
--- a/servo/components/style/values/specified/image.rs +++ b/servo/components/style/values/specified/image.rs @@ -116,19 +116,25 @@ impl ToCss for Gradient { try!(dest.write_str("linear-gradient(")); try!(angle_or_corner.to_css(dest, self.compat_mode)); if angle_or_corner == AngleOrCorner::None { skipcomma = true; } }, GradientKind::Radial(ref shape, ref position) => { try!(dest.write_str("radial-gradient(")); - try!(shape.to_css(dest)); - try!(dest.write_str(" at ")); - try!(position.to_css(dest)); + if self.compat_mode == CompatMode::Modern { + try!(shape.to_css(dest)); + try!(dest.write_str(" at ")); + try!(position.to_css(dest)); + } else { + try!(position.to_css(dest)); + try!(dest.write_str(", ")); + try!(shape.to_css(dest)); + } }, } for stop in &self.stops { if !skipcomma { try!(dest.write_str(", ")); } else { skipcomma = false; } @@ -143,19 +149,26 @@ impl Gradient { pub fn parse_function(context: &ParserContext, input: &mut Parser) -> Result<Gradient, ()> { let parse_linear_gradient = |input: &mut Parser, mode| { input.parse_nested_block(|input| { let kind = try!(GradientKind::parse_linear(context, input, mode)); let stops = try!(input.parse_comma_separated(|i| ColorStop::parse(context, i))); Ok((kind, stops)) }) }; - let parse_radial_gradient = |input: &mut Parser| { + let parse_modern_radial_gradient = |input: &mut Parser| { input.parse_nested_block(|input| { - let kind = try!(GradientKind::parse_radial(context, input)); + let kind = try!(GradientKind::parse_modern_radial(context, input)); + let stops = try!(input.parse_comma_separated(|i| ColorStop::parse(context, i))); + Ok((kind, stops)) + }) + }; + let parse_webkit_radial_gradient = |input: &mut Parser| { + input.parse_nested_block(|input| { + let kind = try!(GradientKind::parse_webkit_radial(context, input)); let stops = try!(input.parse_comma_separated(|i| ColorStop::parse(context, i))); Ok((kind, stops)) }) }; let mut repeating = false; let mut compat_mode = CompatMode::Modern; let (gradient_kind, stops) = match_ignore_ascii_case! { &try!(input.expect_function()), "linear-gradient" => { @@ -170,21 +183,30 @@ impl Gradient { try!(parse_linear_gradient(input, compat_mode)) }, "-webkit-repeating-linear-gradient" => { repeating = true; compat_mode = CompatMode::WebKit; try!(parse_linear_gradient(input, compat_mode)) }, "radial-gradient" => { - try!(parse_radial_gradient(input)) + try!(parse_modern_radial_gradient(input)) + }, + "-webkit-radial-gradient" => { + compat_mode = CompatMode::WebKit; + try!(parse_webkit_radial_gradient(input)) }, "repeating-radial-gradient" => { repeating = true; - try!(parse_radial_gradient(input)) + try!(parse_modern_radial_gradient(input)) + }, + "-webkit-repeating-radial-gradient" => { + repeating = true; + compat_mode = CompatMode::WebKit; + try!(parse_webkit_radial_gradient(input)) }, _ => { return Err(()); } }; // https://drafts.csswg.org/css-images/#typedef-color-stop-list if stops.len() < 2 { return Err(()) } @@ -226,71 +248,59 @@ pub enum CompatMode { impl GradientKind { /// Parses a linear gradient kind from the given arguments. fn parse_linear(context: &ParserContext, input: &mut Parser, mode: CompatMode) -> Result<GradientKind, ()> { let angle_or_corner = try!(AngleOrCorner::parse(context, input, mode)); Ok(GradientKind::Linear(angle_or_corner)) } - /// Parses a radial gradient from the given arguments. - pub fn parse_radial(context: &ParserContext, input: &mut Parser) -> Result<GradientKind, ()> { + /// Parses a modern radial gradient from the given arguments. + pub fn parse_modern_radial(context: &ParserContext, input: &mut Parser) -> Result<GradientKind, ()> { let mut needs_comma = true; - // Ending shape and position can be in various order. Checks all probabilities. let (shape, position) = if let Ok(position) = input.try(|i| parse_position(context, i)) { - // Handle just <position> + // Handle just "at" <position> (EndingShape::Ellipse(LengthOrPercentageOrKeyword::Keyword(SizeKeyword::FarthestCorner)), position) - } else if let Ok((first, second)) = input.try(|i| parse_two_length(context, i)) { - // Handle <LengthOrPercentage> <LengthOrPercentage> <shape>? <position>? - let _ = input.try(|input| input.expect_ident_matching("ellipse")); - (EndingShape::Ellipse(LengthOrPercentageOrKeyword::LengthOrPercentage(first, second)), - input.try(|i| parse_position(context, i)).unwrap_or(Position::center())) - } else if let Ok(length) = input.try(|i| Length::parse(context, i)) { - // Handle <Length> <circle>? <position>? - let _ = input.try(|input| input.expect_ident_matching("circle")); - (EndingShape::Circle(LengthOrKeyword::Length(length)), - input.try(|i| parse_position(context, i)).unwrap_or(Position::center())) - } else if let Ok(keyword) = input.try(SizeKeyword::parse) { - // Handle <keyword> <shape-keyword>? <position>? - let shape = if input.try(|input| input.expect_ident_matching("circle")).is_ok() { - EndingShape::Circle(LengthOrKeyword::Keyword(keyword)) - } else { - let _ = input.try(|input| input.expect_ident_matching("ellipse")); - EndingShape::Ellipse(LengthOrPercentageOrKeyword::Keyword(keyword)) - }; + } else if let Ok(shape) = input.try(|i| parse_shape(context, i, SizeKeyword::parse_modern)) { + // Handle <shape> ["at" <position>]? (shape, input.try(|i| parse_position(context, i)).unwrap_or(Position::center())) } else { - // Handle <shape-keyword> <length>? <position>? - if input.try(|input| input.expect_ident_matching("ellipse")).is_ok() { - // Handle <ellipse> <LengthOrPercentageOrKeyword>? <position>? - let length = input.try(|i| LengthOrPercentageOrKeyword::parse(context, i)) - .unwrap_or(LengthOrPercentageOrKeyword::Keyword(SizeKeyword::FarthestCorner)); - (EndingShape::Ellipse(length), - input.try(|i| parse_position(context, i)).unwrap_or(Position::center())) - } else if input.try(|input| input.expect_ident_matching("circle")).is_ok() { - // Handle <ellipse> <LengthOrKeyword>? <position>? - let length = input.try(|i| LengthOrKeyword::parse(context, i)) - .unwrap_or(LengthOrKeyword::Keyword(SizeKeyword::FarthestCorner)); - (EndingShape::Circle(length), input.try(|i| parse_position(context, i)) - .unwrap_or(Position::center())) - } else { - // If there is no shape keyword, it should set to default. - needs_comma = false; - (EndingShape::Ellipse(LengthOrPercentageOrKeyword::Keyword(SizeKeyword::FarthestCorner)), - input.try(|i| parse_position(context, i)).unwrap_or(Position::center())) - } + // If there is no shape keyword, it should set to default. + needs_comma = false; + (EndingShape::Ellipse(LengthOrPercentageOrKeyword::Keyword(SizeKeyword::FarthestCorner)), + Position::center()) }; if needs_comma { try!(input.expect_comma()); } Ok(GradientKind::Radial(shape, position)) } + + /// Parses a webkit radial gradient from the given arguments. + /// https://compat.spec.whatwg.org/#css-gradients-webkit-radial-gradient + pub fn parse_webkit_radial(context: &ParserContext, input: &mut Parser) -> Result<GradientKind, ()> { + let position = if let Ok(position) = input.try(|i| Position::parse(context, i)) { + try!(input.expect_comma()); + position + } else { + Position::center() + }; + + let shape = if let Ok(shape) = input.try(|i| parse_shape(context, i, SizeKeyword::parse)) { + try!(input.expect_comma()); + shape + } else { + EndingShape::Ellipse(LengthOrPercentageOrKeyword::Keyword(SizeKeyword::Cover)) + }; + + Ok(GradientKind::Radial(shape, position)) + } } /// Specified values for `moz-image-rect` /// -moz-image-rect(<uri>, top, right, bottom, left); #[derive(Clone, PartialEq, Debug)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[allow(missing_docs)] pub struct ImageRect { @@ -353,16 +363,56 @@ fn parse_two_length(context: &ParserCont Ok((first, second)) } fn parse_position(context: &ParserContext, input: &mut Parser) -> Result<Position, ()> { try!(input.expect_ident_matching("at")); input.try(|i| Position::parse(context, i)) } +fn parse_shape<F>(context: &ParserContext, + input: &mut Parser, + parse_size_keyword: F) + -> Result<EndingShape, ()> + where F: FnOnce(&mut Parser) -> Result<SizeKeyword, ()> +{ + if let Ok((first, second)) = input.try(|i| parse_two_length(context, i)) { + // Handle <LengthOrPercentage> <LengthOrPercentage> <shape>? + let _ = input.try(|input| input.expect_ident_matching("ellipse")); + Ok(EndingShape::Ellipse(LengthOrPercentageOrKeyword::LengthOrPercentage(first, second))) + } else if let Ok(length) = input.try(|i| Length::parse(context, i)) { + // Handle <Length> <circle>? + let _ = input.try(|input| input.expect_ident_matching("circle")); + Ok(EndingShape::Circle(LengthOrKeyword::Length(length))) + } else if let Ok(keyword) = input.try(parse_size_keyword) { + // Handle <keyword> <shape-keyword>? + if input.try(|input| input.expect_ident_matching("circle")).is_ok() { + Ok(EndingShape::Circle(LengthOrKeyword::Keyword(keyword))) + } else { + let _ = input.try(|input| input.expect_ident_matching("ellipse")); + Ok(EndingShape::Ellipse(LengthOrPercentageOrKeyword::Keyword(keyword))) + } + } else { + // https://github.com/rust-lang/rust/issues/41272 + if input.try(|input| input.expect_ident_matching("ellipse")).is_ok() { + // Handle <ellipse> <LengthOrPercentageOrKeyword>? + let length = input.try(|i| LengthOrPercentageOrKeyword::parse(context, i)) + .unwrap_or(LengthOrPercentageOrKeyword::Keyword(SizeKeyword::FarthestCorner)); + Ok(EndingShape::Ellipse(length)) + } else if input.try(|input| input.expect_ident_matching("circle")).is_ok() { + // Handle <circle> <LengthOrKeyword>? + let length = input.try(|i| LengthOrKeyword::parse(context, i)) + .unwrap_or(LengthOrKeyword::Keyword(SizeKeyword::FarthestCorner)); + Ok(EndingShape::Circle(length)) + } else { + Err(()) + } + } +} + /// Specified values for an angle or a corner in a linear gradient. #[derive(Clone, PartialEq, Copy, Debug)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[allow(missing_docs)] pub enum AngleOrCorner { Angle(Angle), Corner(Option<HorizontalDirection>, Option<VerticalDirection>), None, @@ -540,9 +590,19 @@ impl ToCss for LengthOrPercentageOrKeywo }, LengthOrPercentageOrKeyword::Keyword(keyword) => keyword.to_css(dest), } } } /// https://drafts.csswg.org/css-images/#typedef-extent-keyword define_css_keyword_enum!(SizeKeyword: "closest-side" => ClosestSide, "farthest-side" => FarthestSide, - "closest-corner" => ClosestCorner, "farthest-corner" => FarthestCorner); + "closest-corner" => ClosestCorner, "farthest-corner" => FarthestCorner, + "contain" => Contain, "cover" => Cover); + +impl SizeKeyword { + fn parse_modern(input: &mut Parser) -> Result<Self, ()> { + match try!(SizeKeyword::parse(input)) { + SizeKeyword::Contain | SizeKeyword::Cover => Err(()), + keyword => Ok(keyword), + } + } +}