From 2ac57a7d8ff4f96c5fdb7c75f624c22c5c29e4b6 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Thu, 20 Apr 2017 22:46:18 +0200 Subject: [PATCH] Fix parsing of -webkit-radial-gradient() It's either keywords or lengths, but not a mix of two. --- components/style/values/specified/image.rs | 121 ++++++++++++--------- 1 file changed, 70 insertions(+), 51 deletions(-) diff --git a/components/style/values/specified/image.rs b/components/style/values/specified/image.rs index 41113d09cb1..d2c749f85e9 100644 --- a/components/style/values/specified/image.rs +++ b/components/style/values/specified/image.rs @@ -257,17 +257,49 @@ impl GradientKind { pub fn parse_modern_radial(context: &ParserContext, input: &mut Parser) -> Result { 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 "at" + // Handle just (EndingShape::Ellipse(LengthOrPercentageOrKeyword::Keyword(SizeKeyword::FarthestCorner)), position) - } else if let Ok(shape) = input.try(|i| parse_shape(context, i, SizeKeyword::parse_modern)) { - // Handle ["at" ]? + } else if let Ok((first, second)) = input.try(|i| parse_two_length(context, i)) { + // Handle ? ? + 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 ? ? + 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_modern) { + // Handle ? ? + 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)) + }; (shape, 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)), - Position::center()) + // Handle ? ? + if input.try(|input| input.expect_ident_matching("ellipse")).is_ok() { + // Handle ? ? + let length = input.try(|i| LengthOrPercentageOrKeyword::parse(context, i, SizeKeyword::parse_modern)) + .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 ? ? + let length = input.try(|i| LengthOrKeyword::parse(context, i, SizeKeyword::parse_modern)) + .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 needs_comma { @@ -287,13 +319,40 @@ impl GradientKind { Position::center() }; - let shape = if let Ok(shape) = input.try(|i| parse_shape(context, i, SizeKeyword::parse)) { - try!(input.expect_comma()); - shape + let mut needs_comma = true; + + // Ending shape and position can be in various order. Checks all probabilities. + let shape = if let Ok((first, second)) = input.try(|i| parse_two_length(context, i)) { + EndingShape::Ellipse(LengthOrPercentageOrKeyword::LengthOrPercentage(first, second)) + } else if let Ok(keyword) = input.try(SizeKeyword::parse) { + // Handle ? + 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 { - EndingShape::Ellipse(LengthOrPercentageOrKeyword::Keyword(SizeKeyword::Cover)) + // Handle ? + if input.try(|input| input.expect_ident_matching("ellipse")).is_ok() { + // Handle ? + let keyword = input.try(SizeKeyword::parse).unwrap_or((SizeKeyword::Cover)); + EndingShape::Ellipse(LengthOrPercentageOrKeyword::Keyword(keyword)) + } else if input.try(|input| input.expect_ident_matching("circle")).is_ok() { + // Handle ? + let keyword = input.try(SizeKeyword::parse).unwrap_or((SizeKeyword::Cover)); + EndingShape::Circle(LengthOrKeyword::Keyword(keyword)) + } else { + // If there is no shape keyword, it should set to default. + needs_comma = false; + EndingShape::Ellipse(LengthOrPercentageOrKeyword::Keyword(SizeKeyword::FarthestCorner)) + } }; + if needs_comma { + try!(input.expect_comma()); + } + Ok(GradientKind::Radial(shape, position)) } } @@ -368,46 +427,6 @@ fn parse_position(context: &ParserContext, input: &mut Parser) -> Result(context: &ParserContext, - input: &mut Parser, - parse_size_keyword: F) - -> Result - where F: Fn(&mut Parser) -> Result -{ - if let Ok((first, second)) = input.try(|i| parse_two_length(context, i)) { - // Handle ? - 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 ? - 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 ? - 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 ? - let length = input.try(|i| LengthOrPercentageOrKeyword::parse(context, i, parse_size_keyword)) - .unwrap_or(LengthOrPercentageOrKeyword::Keyword(SizeKeyword::FarthestCorner)); - Ok(EndingShape::Ellipse(length)) - } else if input.try(|input| input.expect_ident_matching("circle")).is_ok() { - // Handle ? - let length = input.try(|i| LengthOrKeyword::parse(context, i, parse_size_keyword)) - .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))]