From 148247cbce149b8130b71ef73ebb9bdd26995366 Mon Sep 17 00:00:00 2001 From: Anton Lazarev Date: Sat, 10 Nov 2018 11:26:43 -0500 Subject: [PATCH 1/5] add hsl and hsla style colors --- src/css_parser.rs | 288 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 260 insertions(+), 28 deletions(-) diff --git a/src/css_parser.rs b/src/css_parser.rs index 3685e0684..bcf23e631 100644 --- a/src/css_parser.rs +++ b/src/css_parser.rs @@ -447,6 +447,9 @@ pub enum CssColorComponent { Red, Green, Blue, + Hue, + Saturation, + Lightness, Alpha, } @@ -460,6 +463,9 @@ pub enum CssColorParseError<'a> { MissingColorComponent(CssColorComponent), ExtraArguments(&'a str), UnclosedColor(&'a str), + DirectionParseError(String), + UnsupportedDirection(&'a str), + InvalidPercentage(&'a str), } impl<'a> fmt::Display for CssColorParseError<'a> { @@ -474,6 +480,9 @@ impl<'a> fmt::Display for CssColorParseError<'a> { MissingColorComponent(c) => write!(f, "CSS color is missing {:?} component", c), ExtraArguments(a) => write!(f, "Extra argument to CSS color: \"{}\"", a), UnclosedColor(i) => write!(f, "Unclosed color: \"{}\"", i), + DirectionParseError(e) => write!(f, "Could not parse direction argument for CSS color: \"{}\"", e), + UnsupportedDirection(d) => write!(f, "Unsupported direction type for CSS color: \"{}\"", d), + InvalidPercentage(p) => write!(f, "Invalid percentage when parsing CSS color: \"{}\"", p), } } } @@ -490,6 +499,12 @@ impl<'a> From for CssColorParseError<'a> { } } +impl<'a> From> for CssColorParseError<'a> { + fn from(e: CssDirectionParseError) -> Self { + CssColorParseError::DirectionParseError(format!("{:?}", e)) + } +} + #[derive(Debug, Copy, Clone, PartialEq)] pub enum CssImageParseError<'a> { UnclosedQuotes(&'a str), @@ -701,6 +716,18 @@ pub(crate) fn parse_css_color<'a>(input: &'a str) } else { Err(CssColorParseError::UnclosedColor(input)) } + } else if input.starts_with("hsla(") { + if input.ends_with(")") { + parse_color_hsla(&input[5..input.len()-1]) + } else { + Err(CssColorParseError::UnclosedColor(input)) + } + } else if input.starts_with("hsl(") { + if input.ends_with(")") { + parse_color_hsl(&input[4..input.len()-1]) + } else { + Err(CssColorParseError::UnclosedColor(input)) + } } else { parse_color_builtin(input) } @@ -956,15 +983,7 @@ fn parse_color_rgba<'a>(input: &'a str) { let mut components = input.split(',').map(|c| c.trim()); let rgb_color = parse_color_rgb_components(&mut components)?; - let a = components.next().ok_or(CssColorParseError::MissingColorComponent(CssColorComponent::Alpha))?; - if a.is_empty() { - return Err(CssColorParseError::MissingColorComponent(CssColorComponent::Alpha)); - } - let a = a.parse::()?; - if a < 0. || a > 1. { - return Err(CssColorParseError::FloatValueOutOfRange(a)); - } - let a = (a * 256.).min(255.) as u8; + let a = parse_alpha_component(&mut components)?; if let Some(arg) = components.next() { return Err(CssColorParseError::ExtraArguments(arg)); } @@ -995,6 +1014,120 @@ fn parse_color_rgb_components<'a>(components: &mut Iterator) }) } +/// Parse a color of the form 'hsl([0.-360.]deg, [0-100]%, [0-100]%)', without the leading 'hsl(' or +/// trailing ')'. Alpha defaults to 255. +fn parse_color_hsl<'a>(input: &'a str) +-> Result> +{ + let mut components = input.split(',').map(|c| c.trim()); + let color = parse_color_hsl_components(&mut components)?; + if let Some(arg) = components.next() { + return Err(CssColorParseError::ExtraArguments(arg)); + } + Ok(color) +} + +/// Parse a color of the form 'hsla([0.-360.]deg, [0-100]%, [0-100]%, [0.0-1.0])', without the leading +/// 'hsla(' or trailing ')'. +fn parse_color_hsla<'a>(input: &'a str) +-> Result> +{ + let mut components = input.split(',').map(|c| c.trim()); + let rgb_color = parse_color_hsl_components(&mut components)?; + let a = parse_alpha_component(&mut components)?; + if let Some(arg) = components.next() { + return Err(CssColorParseError::ExtraArguments(arg)); + } + Ok(ColorU { a, ..rgb_color }) +} + +/// Parse the color components passed as arguments to an hsl(...) CSS color. +fn parse_color_hsl_components<'a>(components: &mut Iterator) +-> Result> +{ + #[inline] + fn angle_from_str<'a>(components: &mut Iterator, which: CssColorComponent) + -> Result> + { + let c = components.next().ok_or(CssColorParseError::MissingColorComponent(which))?; + if c.is_empty() { + return Err(CssColorParseError::MissingColorComponent(which)); + } + let dir = parse_direction(c)?; + match dir { + Direction::Angle(deg) => Ok(deg.get()), + Direction::FromTo(_, _) => return Err(CssColorParseError::UnsupportedDirection(c)), + } + } + + #[inline] + fn percent_from_str<'a>(components: &mut Iterator, which: CssColorComponent) + -> Result> + { + let c = components.next().ok_or(CssColorParseError::MissingColorComponent(which))?; + if c.is_empty() { + return Err(CssColorParseError::MissingColorComponent(which)); + } + match parse_percentage(c) { + Some(percentage) => Ok(percentage.get()), + None => Err(CssColorParseError::InvalidPercentage(c)), + } + } + + /// Adapted from [https://en.wikipedia.org/wiki/HSL_and_HSV#Converting_to_RGB] + #[inline] + fn hsl_to_rgb<'a>(h: f32, s: f32, l: f32) -> (u8, u8, u8) { + let s = s / 100.; + let l = l / 100.; + let c = (1. - (2. * l - 1.).abs()) * s; + let h = h / 60.; + let x = c * (1. - ((h % 2.) - 1.).abs()); + let (r1, g1, b1) = match h as u8 { + 0 => (c, x, 0.), + 1 => (x, c, 0.), + 2 => (0., c, x), + 3 => (0., x, c), + 4 => (x, 0., c), + 5 => (c, 0., x), + _ => { + println!("h is {}", h); + unreachable!(); + } + }; + let m = l - c / 2.; + ( + ((r1 + m) * 256.).min(255.) as u8, + ((g1 + m) * 256.).min(255.) as u8, + ((b1 + m) * 256.).min(255.) as u8, + ) + } + + let (h, s, l) = ( + angle_from_str(components, CssColorComponent::Hue)?, + percent_from_str(components, CssColorComponent::Saturation)?, + percent_from_str(components, CssColorComponent::Lightness)?, + ); + + let (r, g, b) = hsl_to_rgb(h, s, l); + + Ok(ColorU { r, g, b, a: 255 }) +} + +#[inline] +fn parse_alpha_component<'a>(components: &mut Iterator) -> Result> { + let a = components.next().ok_or(CssColorParseError::MissingColorComponent(CssColorComponent::Alpha))?; + if a.is_empty() { + return Err(CssColorParseError::MissingColorComponent(CssColorComponent::Alpha)); + } + let a = a.parse::()?; + if a < 0. || a > 1. { + return Err(CssColorParseError::FloatValueOutOfRange(a)); + } + let a = (a * 256.).min(255.) as u8; + Ok(a) +} + + /// Parse a background color, WITHOUT THE HASH /// /// "00FFFF" -> ColorF { r: 0, g: 255, b: 255}) @@ -1623,15 +1756,6 @@ impl Direction { // hypotenuse_len is the length of the center of the rect to the corners let hypotenuse_len = (((width_half * width_half) + (height_half * height_half)) as f64).sqrt(); - // clamp the degree to 360 (so 410deg = 50deg) - let mut deg = deg % 360.0; - if deg < 0.0 { - deg = 360.0 + deg; - } - - // now deg is in the range of +0..+360 - debug_assert!(deg >= 0.0 && deg <= 360.0); - // The corner also serves to determine what quadrant we're in // Get the quadrant (corner) the angle is in and get the degree associated // with that corner. @@ -2087,23 +2211,28 @@ fn parse_direction<'a>(input: &'a str) }; if let Some(angle_type) = angle { - match angle_type { + let deg = match angle_type { AngleType::Deg => { - return Ok(Direction::Angle(FloatValue::new( - first_input.split("deg").next().unwrap().parse::()? - ))); + first_input.split("deg").next().unwrap().parse::()? }, AngleType::Rad => { - return Ok(Direction::Angle(FloatValue::new( - first_input.split("rad").next().unwrap().parse::()? * 180.0 / PI - ))); + first_input.split("rad").next().unwrap().parse::()? * 180.0 / PI }, AngleType::Gon => { - return Ok(Direction::Angle(FloatValue::new( - first_input.split("grad").next().unwrap().parse::()? / 400.0 * 360.0 - ))); + first_input.split("grad").next().unwrap().parse::()? / 400.0 * 360.0 }, + }; + + // clamp the degree to 360 (so 410deg = 50deg) + let mut deg = deg % 360.0; + if deg < 0.0 { + deg = 360.0 + deg; } + + // now deg is in the range of +0..+360 + debug_assert!(deg >= 0.0 && deg <= 360.0); + + return Ok(Direction::Angle(FloatValue::new(deg))); } // if we get here, the input is definitely not an angle @@ -3133,6 +3262,109 @@ mod css_tests { assert_eq!(parse_css_color("rgba(50, 60, 70, )"), Err(CssColorParseError::MissingColorComponent(CssColorComponent::Alpha))); } + #[test] + fn test_parse_css_color_18() { + assert_eq!(parse_css_color("hsl(0deg, 100%, 100%)"), Ok(ColorU { r: 255, g: 255, b: 255, a: 255 })); + } + + #[test] + fn test_parse_css_color_19() { + assert_eq!(parse_css_color("hsl(0deg, 100%, 50%)"), Ok(ColorU { r: 255, g: 0, b: 0, a: 255 })); + } + + #[test] + fn test_parse_css_color_20() { + assert_eq!(parse_css_color("hsl(170deg, 50%, 75%)"), Ok(ColorU { r: 160, g: 224, b: 213, a: 255 })); + } + + #[test] + fn test_parse_css_color_21() { + assert_eq!(parse_css_color("hsla(190deg, 50%, 75%, 1.0)"), Ok(ColorU { r: 160, g: 213, b: 224, a: 255 })); + } + + #[test] + fn test_parse_css_color_22() { + assert_eq!(parse_css_color("hsla(120deg, 0%, 25%, 0.25)"), Ok(ColorU { r: 64, g: 64, b: 64, a: 64 })); + } + + #[test] + fn test_parse_css_color_23() { + assert_eq!(parse_css_color("hsla(120deg, 0%, 0%, 0.5)"), Ok(ColorU { r: 0, g: 0, b: 0, a: 128 })); + } + + #[test] + fn test_parse_css_color_24() { + assert_eq!(parse_css_color("hsla(60.9deg, 80.3%, 40%, 0.5)"), Ok(ColorU { r: 182, g: 184, b: 20, a: 128 })); + } + + #[test] + fn test_parse_css_color_25() { + assert_eq!(parse_css_color("hsla(60.9rad, 80.3%, 40%, 0.5)"), Ok(ColorU { r: 45, g: 20, b: 184, a: 128 })); + } + + #[test] + fn test_parse_css_color_26() { + assert_eq!(parse_css_color("hsla(60.9grad, 80.3%, 40%, 0.5)"), Ok(ColorU { r: 184, g: 170, b: 20, a: 128 })); + } + + #[test] + fn test_parse_direction() { + let first_input = "60.9grad"; + let e = FloatValue::new(first_input.split("grad").next().unwrap().parse::().expect("Parseable float") / 400.0 * 360.0); + assert_eq!(e, FloatValue::new(60.9 / 400.0 * 360.0)); + assert_eq!(parse_direction("60.9grad"), Ok(Direction::Angle(FloatValue::new(60.9 / 400.0 * 360.0)))); + } + + #[test] + fn test_parse_float_value() { + assert_eq!(parse_float_value("60.9"), Ok(FloatValue::new(60.9))); + } + + #[test] + fn test_parse_css_color_27() { + assert_eq!(parse_css_color("hsla(240, 0%, 0%, 0.5)"), Err(CssColorParseError::DirectionParseError("InvalidArguments(\"240\")".to_owned()))); + } + + #[test] + fn test_parse_css_color_28() { + assert_eq!(parse_css_color("hsla(240deg, 0, 0%, 0.5)"), Err(CssColorParseError::InvalidPercentage("0"))); + } + + #[test] + fn test_parse_css_color_29() { + assert_eq!(parse_css_color("hsla(240deg, 0%, 0, 0.5)"), Err(CssColorParseError::InvalidPercentage("0"))); + } + + #[test] + fn test_parse_css_color_30() { + assert_eq!(parse_css_color("hsla(240deg, 0%, 0%, )"), Err(CssColorParseError::MissingColorComponent(CssColorComponent::Alpha))) + } + + #[test] + fn test_parse_css_color_31() { + assert_eq!(parse_css_color("hsl(, 0%, 0%, )"), Err(CssColorParseError::MissingColorComponent(CssColorComponent::Hue))) + } + + #[test] + fn test_parse_css_color_32() { + assert_eq!(parse_css_color("hsl(240deg , )"), Err(CssColorParseError::MissingColorComponent(CssColorComponent::Saturation))) + } + + #[test] + fn test_parse_css_color_33() { + assert_eq!(parse_css_color("hsl(240deg, 0%, )"), Err(CssColorParseError::MissingColorComponent(CssColorComponent::Lightness))) + } + + #[test] + fn test_parse_css_color_34() { + assert_eq!(parse_css_color("hsl(240deg, 0%, 0%, )"), Err(CssColorParseError::ExtraArguments(""))) + } + + #[test] + fn test_parse_css_color_35() { + assert_eq!(parse_css_color("hsla(240deg, 0%, 0% )"), Err(CssColorParseError::MissingColorComponent(CssColorComponent::Alpha))) + } + #[test] fn test_parse_pixel_value_1() { assert_eq!(parse_pixel_value("15px"), Ok(PixelValue::px(15.0))); From ac4bcd3c13108b374e35a0d4be5106d64032c04c Mon Sep 17 00:00:00 2001 From: Anton Lazarev Date: Sat, 10 Nov 2018 12:46:52 -0500 Subject: [PATCH 2/5] wrap DirectionParseError for CssColorParseError::DirectionParseError --- src/css_parser.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/css_parser.rs b/src/css_parser.rs index bcf23e631..7461e8b40 100644 --- a/src/css_parser.rs +++ b/src/css_parser.rs @@ -463,7 +463,7 @@ pub enum CssColorParseError<'a> { MissingColorComponent(CssColorComponent), ExtraArguments(&'a str), UnclosedColor(&'a str), - DirectionParseError(String), + DirectionParseError(CssDirectionParseError<'a>), UnsupportedDirection(&'a str), InvalidPercentage(&'a str), } @@ -499,11 +499,7 @@ impl<'a> From for CssColorParseError<'a> { } } -impl<'a> From> for CssColorParseError<'a> { - fn from(e: CssDirectionParseError) -> Self { - CssColorParseError::DirectionParseError(format!("{:?}", e)) - } -} +impl_from!(CssDirectionParseError<'a>, CssColorParseError::DirectionParseError); #[derive(Debug, Copy, Clone, PartialEq)] pub enum CssImageParseError<'a> { @@ -3322,7 +3318,7 @@ mod css_tests { #[test] fn test_parse_css_color_27() { - assert_eq!(parse_css_color("hsla(240, 0%, 0%, 0.5)"), Err(CssColorParseError::DirectionParseError("InvalidArguments(\"240\")".to_owned()))); + assert_eq!(parse_css_color("hsla(240, 0%, 0%, 0.5)"), Err(CssColorParseError::DirectionParseError(parse_direction("240").err().unwrap()))); } #[test] From d29a8b01bc9f28dfbe729d6ed2032f45b8e621a8 Mon Sep 17 00:00:00 2001 From: Anton Lazarev Date: Sat, 10 Nov 2018 13:08:07 -0500 Subject: [PATCH 3/5] deduplicate rgb/rgba and hsl/hsla --- src/css_parser.rs | 57 ++++++++++++++++------------------------------- 1 file changed, 19 insertions(+), 38 deletions(-) diff --git a/src/css_parser.rs b/src/css_parser.rs index 7461e8b40..de079241e 100644 --- a/src/css_parser.rs +++ b/src/css_parser.rs @@ -702,25 +702,25 @@ pub(crate) fn parse_css_color<'a>(input: &'a str) parse_color_no_hash(&input[1..]) } else if input.starts_with("rgba(") { if input.ends_with(")") { - parse_color_rgba(&input[5..input.len()-1]) + parse_color_rgb(&input[5..input.len()-1], true) } else { Err(CssColorParseError::UnclosedColor(input)) } } else if input.starts_with("rgb(") { if input.ends_with(")") { - parse_color_rgb(&input[4..input.len()-1]) + parse_color_rgb(&input[4..input.len()-1], false) } else { Err(CssColorParseError::UnclosedColor(input)) } } else if input.starts_with("hsla(") { if input.ends_with(")") { - parse_color_hsla(&input[5..input.len()-1]) + parse_color_hsl(&input[5..input.len()-1], true) } else { Err(CssColorParseError::UnclosedColor(input)) } } else if input.starts_with("hsl(") { if input.ends_with(")") { - parse_color_hsl(&input[4..input.len()-1]) + parse_color_hsl(&input[4..input.len()-1], false) } else { Err(CssColorParseError::UnclosedColor(input)) } @@ -959,27 +959,18 @@ fn parse_color_builtin<'a>(input: &'a str) parse_color_no_hash(color) } -/// Parse a color of the form 'rgb([0-255], [0-255], [0-255])', without the leading 'rgb(' or -/// trailing ')'. Alpha defaults to 255. -fn parse_color_rgb<'a>(input: &'a str) --> Result> -{ - let mut components = input.split(',').map(|c| c.trim()); - let color = parse_color_rgb_components(&mut components)?; - if let Some(arg) = components.next() { - return Err(CssColorParseError::ExtraArguments(arg)); - } - Ok(color) -} - -/// Parse a color of the form 'rgba([0-255], [0-255], [0-255], [0.0-1.0])', without the leading -/// 'rgba(' or trailing ')'. -fn parse_color_rgba<'a>(input: &'a str) +/// Parse a color of the form 'rgb([0-255], [0-255], [0-255])', or 'rgba([0-255], [0-255], [0-255], +/// [0.-1.])' without the leading 'rgb[a](' or trailing ')'. Alpha defaults to 255. +fn parse_color_rgb<'a>(input: &'a str, parse_alpha: bool) -> Result> { let mut components = input.split(',').map(|c| c.trim()); let rgb_color = parse_color_rgb_components(&mut components)?; - let a = parse_alpha_component(&mut components)?; + let a = if parse_alpha { + parse_alpha_component(&mut components)? + } else { + 255 + }; if let Some(arg) = components.next() { return Err(CssColorParseError::ExtraArguments(arg)); } @@ -1010,27 +1001,17 @@ fn parse_color_rgb_components<'a>(components: &mut Iterator) }) } -/// Parse a color of the form 'hsl([0.-360.]deg, [0-100]%, [0-100]%)', without the leading 'hsl(' or -/// trailing ')'. Alpha defaults to 255. -fn parse_color_hsl<'a>(input: &'a str) --> Result> -{ - let mut components = input.split(',').map(|c| c.trim()); - let color = parse_color_hsl_components(&mut components)?; - if let Some(arg) = components.next() { - return Err(CssColorParseError::ExtraArguments(arg)); - } - Ok(color) -} - -/// Parse a color of the form 'hsla([0.-360.]deg, [0-100]%, [0-100]%, [0.0-1.0])', without the leading -/// 'hsla(' or trailing ')'. -fn parse_color_hsla<'a>(input: &'a str) +/// Parse a color of the form 'hsl([0.-360.]deg, [0-100]%, [0-100]%)', or 'hsla([0.-360.]deg, [0-100]%, [0-100]%, [0.-1.])' without the leading 'hsl[a](' or trailing ')'. Alpha defaults to 255. +fn parse_color_hsl<'a>(input: &'a str, parse_alpha: bool) -> Result> { let mut components = input.split(',').map(|c| c.trim()); let rgb_color = parse_color_hsl_components(&mut components)?; - let a = parse_alpha_component(&mut components)?; + let a = if parse_alpha { + parse_alpha_component(&mut components)? + } else { + 255 + }; if let Some(arg) = components.next() { return Err(CssColorParseError::ExtraArguments(arg)); } From ec8d9b42f1a0ce234057bdf044de87ab034f6e11 Mon Sep 17 00:00:00 2001 From: Anton Lazarev Date: Sat, 10 Nov 2018 17:01:52 -0500 Subject: [PATCH 4/5] add trailing 0 to floating point numbers --- src/css_parser.rs | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/css_parser.rs b/src/css_parser.rs index de079241e..7706a793e 100644 --- a/src/css_parser.rs +++ b/src/css_parser.rs @@ -960,7 +960,7 @@ fn parse_color_builtin<'a>(input: &'a str) } /// Parse a color of the form 'rgb([0-255], [0-255], [0-255])', or 'rgba([0-255], [0-255], [0-255], -/// [0.-1.])' without the leading 'rgb[a](' or trailing ')'. Alpha defaults to 255. +/// [0.0-1.0])' without the leading 'rgb[a](' or trailing ')'. Alpha defaults to 255. fn parse_color_rgb<'a>(input: &'a str, parse_alpha: bool) -> Result> { @@ -1001,7 +1001,7 @@ fn parse_color_rgb_components<'a>(components: &mut Iterator) }) } -/// Parse a color of the form 'hsl([0.-360.]deg, [0-100]%, [0-100]%)', or 'hsla([0.-360.]deg, [0-100]%, [0-100]%, [0.-1.])' without the leading 'hsl[a](' or trailing ')'. Alpha defaults to 255. +/// Parse a color of the form 'hsl([0.0-360.0]deg, [0-100]%, [0-100]%)', or 'hsla([0.0-360.0]deg, [0-100]%, [0-100]%, [0.0-1.0])' without the leading 'hsl[a](' or trailing ')'. Alpha defaults to 255. fn parse_color_hsl<'a>(input: &'a str, parse_alpha: bool) -> Result> { @@ -1054,28 +1054,28 @@ fn parse_color_hsl_components<'a>(components: &mut Iterator) /// Adapted from [https://en.wikipedia.org/wiki/HSL_and_HSV#Converting_to_RGB] #[inline] fn hsl_to_rgb<'a>(h: f32, s: f32, l: f32) -> (u8, u8, u8) { - let s = s / 100.; - let l = l / 100.; - let c = (1. - (2. * l - 1.).abs()) * s; - let h = h / 60.; - let x = c * (1. - ((h % 2.) - 1.).abs()); + let s = s / 100.0; + let l = l / 100.0; + let c = (1.0 - (2.0 * l - 1.0).abs()) * s; + let h = h / 60.0; + let x = c * (1.0 - ((h % 2.0) - 1.0).abs()); let (r1, g1, b1) = match h as u8 { - 0 => (c, x, 0.), - 1 => (x, c, 0.), - 2 => (0., c, x), - 3 => (0., x, c), - 4 => (x, 0., c), - 5 => (c, 0., x), + 0 => (c, x, 0.0), + 1 => (x, c, 0.0), + 2 => (0.0, c, x), + 3 => (0.0, x, c), + 4 => (x, 0.0, c), + 5 => (c, 0.0, x), _ => { println!("h is {}", h); unreachable!(); } }; - let m = l - c / 2.; + let m = l - c / 2.0; ( - ((r1 + m) * 256.).min(255.) as u8, - ((g1 + m) * 256.).min(255.) as u8, - ((b1 + m) * 256.).min(255.) as u8, + ((r1 + m) * 256.0).min(255.0) as u8, + ((g1 + m) * 256.0).min(255.0) as u8, + ((b1 + m) * 256.0).min(255.0) as u8, ) } @@ -1097,10 +1097,10 @@ fn parse_alpha_component<'a>(components: &mut Iterator) -> Result< return Err(CssColorParseError::MissingColorComponent(CssColorComponent::Alpha)); } let a = a.parse::()?; - if a < 0. || a > 1. { + if a < 0.0 || a > 1.0 { return Err(CssColorParseError::FloatValueOutOfRange(a)); } - let a = (a * 256.).min(255.) as u8; + let a = (a * 256.0).min(255.0) as u8; Ok(a) } @@ -3181,7 +3181,7 @@ mod css_tests { #[test] fn test_parse_css_color_6() { - assert_eq!(parse_css_color("rgba(192, 14, 12, 80)"), Err(CssColorParseError::FloatValueOutOfRange(80.))); + assert_eq!(parse_css_color("rgba(192, 14, 12, 80)"), Err(CssColorParseError::FloatValueOutOfRange(80.0))); } #[test] From 3b25580e1fc173ed6d3c6c5497bdb8bc24aafa99 Mon Sep 17 00:00:00 2001 From: Anton Lazarev Date: Sat, 10 Nov 2018 17:21:41 -0500 Subject: [PATCH 5/5] simplify error handling --- src/css_parser.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/css_parser.rs b/src/css_parser.rs index 7706a793e..7c761e2a1 100644 --- a/src/css_parser.rs +++ b/src/css_parser.rs @@ -1045,10 +1045,9 @@ fn parse_color_hsl_components<'a>(components: &mut Iterator) if c.is_empty() { return Err(CssColorParseError::MissingColorComponent(which)); } - match parse_percentage(c) { - Some(percentage) => Ok(percentage.get()), - None => Err(CssColorParseError::InvalidPercentage(c)), - } + parse_percentage(c) + .ok_or(CssColorParseError::InvalidPercentage(c)) + .and_then(|p| Ok(p.get())) } /// Adapted from [https://en.wikipedia.org/wiki/HSL_and_HSV#Converting_to_RGB]