diff --git a/components/style/parser.rs b/components/style/parser.rs index 9874bf49f54..8bfefc414cb 100644 --- a/components/style/parser.rs +++ b/components/style/parser.rs @@ -20,6 +20,9 @@ bitflags! { /// to be in user units (px). /// https://www.w3.org/TR/SVG/coords.html#Units const PARSING_MODE_ALLOW_UNITLESS_LENGTH = 0x01, + /// In SVG, out-of-range values are not treated as an error in parsing. + /// https://www.w3.org/TR/SVG/implnote.html#RangeClamping + const PARSING_MODE_ALLOW_ALL_NUMERIC_VALUES = 0x02, } } @@ -28,6 +31,11 @@ impl ParsingMode { pub fn allows_unitless_lengths(&self) -> bool { self.intersects(PARSING_MODE_ALLOW_UNITLESS_LENGTH) } + + /// Whether the parsing mode allows all numeric values. + pub fn allows_all_numeric_values(&self) -> bool { + self.intersects(PARSING_MODE_ALLOW_ALL_NUMERIC_VALUES) + } } /// Asserts that all ParsingMode flags have a matching ParsingMode value in gecko. @@ -39,12 +47,12 @@ pub fn assert_parsing_mode_match() { macro_rules! check_parsing_modes { ( $( $a:ident => $b:ident ),*, ) => { if cfg!(debug_assertions) { - let mut hints = ParsingMode::all(); + let mut modes = ParsingMode::all(); $( assert_eq!(structs::$a as usize, $b.bits() as usize, stringify!($b)); - hints.remove($b); + modes.remove($b); )* - assert_eq!(hints, ParsingMode::empty(), "all ParsingMode bits should have an assertion"); + assert_eq!(modes, ParsingMode::empty(), "all ParsingMode bits should have an assertion"); } } } @@ -52,6 +60,7 @@ pub fn assert_parsing_mode_match() { check_parsing_modes! { ParsingMode_Default => PARSING_MODE_DEFAULT, ParsingMode_AllowUnitlessLength => PARSING_MODE_ALLOW_UNITLESS_LENGTH, + ParsingMode_AllowAllNumericValues => PARSING_MODE_ALLOW_ALL_NUMERIC_VALUES, } } diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index 8cd5ebdd793..31990fba71a 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -632,12 +632,20 @@ impl Number { #[allow(missing_docs)] pub fn parse_non_negative(context: &ParserContext, input: &mut Parser) -> Result { - parse_number_with_clamping_mode(context, input, AllowedNumericType::NonNegative) + if context.parsing_mode.allows_all_numeric_values() { + parse_number(context, input) + } else { + parse_number_with_clamping_mode(context, input, AllowedNumericType::NonNegative) + } } #[allow(missing_docs)] pub fn parse_at_least_one(context: &ParserContext, input: &mut Parser) -> Result { - parse_number_with_clamping_mode(context, input, AllowedNumericType::AtLeastOne) + if context.parsing_mode.allows_all_numeric_values() { + parse_number(context, input) + } else { + parse_number_with_clamping_mode(context, input, AllowedNumericType::AtLeastOne) + } } } diff --git a/tests/unit/style/parsing/value.rs b/tests/unit/style/parsing/value.rs index 2151529a293..3a1f69746e4 100644 --- a/tests/unit/style/parsing/value.rs +++ b/tests/unit/style/parsing/value.rs @@ -3,8 +3,13 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use app_units::Au; +use cssparser::Parser; +use media_queries::CSSErrorReporterTest; +use style::context::QuirksMode; +use style::parser::{PARSING_MODE_ALLOW_ALL_NUMERIC_VALUES, ParserContext}; +use style::stylesheets::{CssRuleType, Origin}; use style::values::HasViewportPercentage; -use style::values::specified::{AbsoluteLength, NoCalcLength, ViewportPercentageLength}; +use style::values::specified::{AbsoluteLength, NoCalcLength, Number, ViewportPercentageLength}; #[test] fn length_has_viewport_percentage() { @@ -13,3 +18,18 @@ fn length_has_viewport_percentage() { let l = NoCalcLength::Absolute(AbsoluteLength::Px(Au(100).to_f32_px())); assert!(!l.has_viewport_percentage()); } + +#[test] +fn test_parsing_allo_all_numeric_values() { + // In SVG length mode, non-zero lengths are assumed to be px. + let url = ::servo_url::ServoUrl::parse("http://localhost").unwrap(); + let reporter = CSSErrorReporterTest; + let context = ParserContext::new(Origin::Author, &url, &reporter, + Some(CssRuleType::Style), PARSING_MODE_ALLOW_ALL_NUMERIC_VALUES, + QuirksMode::NoQuirks); + let mut parser = Parser::new("-1"); + let result = Number::parse_non_negative(&context, &mut parser); + assert!(result.is_ok()); + assert_eq!(result.unwrap(), Number::new(-1.)); +} +