diff --git a/components/style/properties/longhand/inherited_text.mako.rs b/components/style/properties/longhand/inherited_text.mako.rs index 9c63fd45686..741806e9ef5 100644 --- a/components/style/properties/longhand/inherited_text.mako.rs +++ b/components/style/properties/longhand/inherited_text.mako.rs @@ -48,23 +48,27 @@ pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result { use cssparser::Token; use std::ascii::AsciiExt; - input.try(specified::LengthOrPercentage::parse_non_negative) - .map(SpecifiedValue::LengthOrPercentage) + // We try to parse as a Number first because, for 'line-height', we want "0" to be + // parsed as a plain Number rather than a Length (0px); this matches the behaviour + // of all major browsers + input.try(specified::Number::parse_non_negative) + .map(|n| SpecifiedValue::Number(n.0)) .or_else(|()| { - match try!(input.next()) { - Token::Number(ref value) if value.value >= 0. => { - Ok(SpecifiedValue::Number(value.value)) + input.try(specified::LengthOrPercentage::parse_non_negative) + .map(SpecifiedValue::LengthOrPercentage) + .or_else(|()| { + match try!(input.next()) { + Token::Ident(ref value) if value.eq_ignore_ascii_case("normal") => { + Ok(SpecifiedValue::Normal) + } + % if product == "gecko": + Token::Ident(ref value) if value.eq_ignore_ascii_case("-moz-block-height") => { + Ok(SpecifiedValue::MozBlockHeight) + } + % endif + _ => Err(()), } - Token::Ident(ref value) if value.eq_ignore_ascii_case("normal") => { - Ok(SpecifiedValue::Normal) - } - % if product == "gecko": - Token::Ident(ref value) if value.eq_ignore_ascii_case("-moz-block-height") => { - Ok(SpecifiedValue::MozBlockHeight) - } - % endif - _ => Err(()), - } + }) }) } pub mod computed_value { diff --git a/components/style/values/specified/length.rs b/components/style/values/specified/length.rs index 601056d6447..9cc284fd774 100644 --- a/components/style/values/specified/length.rs +++ b/components/style/values/specified/length.rs @@ -1196,10 +1196,13 @@ pub type LengthOrNumber = Either; impl LengthOrNumber { /// Parse a non-negative LengthOrNumber. pub fn parse_non_negative(input: &mut Parser) -> Result { - if let Ok(v) = input.try(Length::parse_non_negative) { - Ok(Either::First(v)) + // We try to parse as a Number first because, for cases like LengthOrNumber, + // we want "0" to be parsed as a plain Number rather than a Length (0px); this + // matches the behaviour of all major browsers + if let Ok(v) = input.try(Number::parse_non_negative) { + Ok(Either::Second(v)) } else { - Number::parse_non_negative(input).map(Either::Second) + Length::parse_non_negative(input).map(Either::First) } } } diff --git a/tests/unit/style/parsing/border.rs b/tests/unit/style/parsing/border.rs index 6ddb7824c05..7eab37513cf 100644 --- a/tests/unit/style/parsing/border.rs +++ b/tests/unit/style/parsing/border.rs @@ -104,3 +104,21 @@ fn border_image_outset_should_error_on_negative_number() { let result = border_image_outset::parse(&context, &mut parser); assert_eq!(result, Err(())); } + +#[test] +fn border_image_outset_should_return_number_on_plain_zero() { + let url = ServoUrl::parse("http://localhost").unwrap(); + let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest)); + let mut parser = Parser::new("0"); + let result = border_image_outset::parse(&context, &mut parser); + assert_eq!(result.unwrap(), parse_longhand!(border_image_outset, "0")); +} + +#[test] +fn border_image_outset_should_return_length_on_length_zero() { + let url = ServoUrl::parse("http://localhost").unwrap(); + let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest)); + let mut parser = Parser::new("0em"); + let result = border_image_outset::parse(&context, &mut parser); + assert_eq!(result.unwrap(), parse_longhand!(border_image_outset, "0em")); +} diff --git a/tests/unit/style/parsing/inherited_text.rs b/tests/unit/style/parsing/inherited_text.rs index faaa1cce02e..fc77e7318e5 100644 --- a/tests/unit/style/parsing/inherited_text.rs +++ b/tests/unit/style/parsing/inherited_text.rs @@ -102,3 +102,29 @@ fn webkit_text_stroke_shorthand_should_parse_properly() { assert_eq!(result._webkit_text_stroke_color.unwrap(), parse_longhand!(_webkit_text_stroke_color, "red")); assert_eq!(result._webkit_text_stroke_width.unwrap(), parse_longhand!(_webkit_text_stroke_width, "thin")); } + +#[test] +fn line_height_should_return_number_on_plain_zero() { + use media_queries::CSSErrorReporterTest; + use servo_url::ServoUrl; + use style::properties::longhands::line_height; + + let url = ServoUrl::parse("http://localhost").unwrap(); + let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest)); + let mut parser = Parser::new("0"); + let result = line_height::parse(&context, &mut parser); + assert_eq!(result.unwrap(), parse_longhand!(line_height, "0")); +} + +#[test] +fn line_height_should_return_length_on_length_zero() { + use media_queries::CSSErrorReporterTest; + use servo_url::ServoUrl; + use style::properties::longhands::line_height; + + let url = ServoUrl::parse("http://localhost").unwrap(); + let context = ParserContext::new(Origin::Author, &url, Box::new(CSSErrorReporterTest)); + let mut parser = Parser::new("0px"); + let result = line_height::parse(&context, &mut parser); + assert_eq!(result.unwrap(), parse_longhand!(line_height, "0px")); +}