style: Deduplicate Angle parsing code.

This commit is contained in:
Emilio Cobos Álvarez 2017-12-02 15:30:20 +01:00
parent 55439e6222
commit 3631b1e197
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
3 changed files with 41 additions and 26 deletions

View file

@ -102,23 +102,25 @@ impl AsRef<ComputedAngle> for Angle {
} }
} }
/// Whether to allow parsing an unitless zero as a valid angle.
///
/// This should always be `No`, except for exceptions like:
///
/// https://github.com/w3c/fxtf-drafts/issues/228
///
/// See also: https://github.com/w3c/csswg-drafts/issues/1162.
enum AllowUnitlessZeroAngle {
Yes,
No,
}
impl Parse for Angle { impl Parse for Angle {
/// Parses an angle according to CSS-VALUES § 6.1. /// Parses an angle according to CSS-VALUES § 6.1.
fn parse<'i, 't>( fn parse<'i, 't>(
context: &ParserContext, context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
// FIXME: remove clone() when lifetimes are non-lexical Self::parse_internal(context, input, AllowUnitlessZeroAngle::No)
let token = input.next()?.clone();
match token {
Token::Dimension { value, ref unit, .. } => {
Angle::parse_dimension(value, unit, /* from_calc = */ false)
}
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
return input.parse_nested_block(|i| CalcNode::parse_angle(context, i))
}
_ => Err(())
}.map_err(|()| input.new_unexpected_token_error(token.clone()))
} }
} }
@ -127,9 +129,8 @@ impl Angle {
pub fn parse_dimension( pub fn parse_dimension(
value: CSSFloat, value: CSSFloat,
unit: &str, unit: &str,
from_calc: bool) from_calc: bool,
-> Result<Angle, ()> ) -> Result<Angle, ()> {
{
let angle = match_ignore_ascii_case! { unit, let angle = match_ignore_ascii_case! { unit,
"deg" => Angle::from_degrees(value, from_calc), "deg" => Angle::from_degrees(value, from_calc),
"grad" => Angle::from_gradians(value, from_calc), "grad" => Angle::from_gradians(value, from_calc),
@ -140,23 +141,33 @@ impl Angle {
Ok(angle) Ok(angle)
} }
/// Parse an angle, including unitless 0 degree. /// Parse an `<angle>` allowing unitless zero to represent a zero angle.
/// ///
/// Note that numbers without any AngleUnit, including unitless 0 angle, /// See the comment in `AllowUnitlessZeroAngle` for why.
/// should be invalid. However, some properties still accept unitless 0 pub fn parse_with_unitless<'i, 't>(
/// angle and stores it as '0deg'. context: &ParserContext,
/// input: &mut Parser<'i, 't>,
/// We can remove this and get back to the unified version Angle::parse once ) -> Result<Self, ParseError<'i>> {
/// https://github.com/w3c/csswg-drafts/issues/1162 is resolved. Self::parse_internal(context, input, AllowUnitlessZeroAngle::Yes)
pub fn parse_with_unitless<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) }
-> Result<Self, ParseError<'i>> {
fn parse_internal<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
allow_unitless_zero: AllowUnitlessZeroAngle,
) -> Result<Self, ParseError<'i>> {
// FIXME: remove clone() when lifetimes are non-lexical // FIXME: remove clone() when lifetimes are non-lexical
let token = input.next()?.clone(); let token = input.next()?.clone();
match token { match token {
Token::Dimension { value, ref unit, .. } => { Token::Dimension { value, ref unit, .. } => {
Angle::parse_dimension(value, unit, /* from_calc = */ false) Angle::parse_dimension(value, unit, /* from_calc = */ false)
} }
Token::Number { value, .. } if value == 0. => Ok(Angle::zero()), Token::Number { value, .. } if value == 0. => {
match allow_unitless_zero {
AllowUnitlessZeroAngle::Yes => Ok(Angle::zero()),
AllowUnitlessZeroAngle::No => Err(()),
}
},
Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => { Token::Function(ref name) if name.eq_ignore_ascii_case("calc") => {
return input.parse_nested_block(|i| CalcNode::parse_angle(context, i)) return input.parse_nested_block(|i| CalcNode::parse_angle(context, i))
} }

View file

@ -714,6 +714,8 @@ impl LineDirection {
let mut _angle = if *compat_mode == CompatMode::Moz { let mut _angle = if *compat_mode == CompatMode::Moz {
input.try(|i| Angle::parse(context, i)).ok() input.try(|i| Angle::parse(context, i)).ok()
} else { } else {
// Gradients allow unitless zero angles as an exception, see:
// https://github.com/w3c/csswg-drafts/issues/1162
if let Ok(angle) = input.try(|i| Angle::parse_with_unitless(context, i)) { if let Ok(angle) = input.try(|i| Angle::parse_with_unitless(context, i)) {
return Ok(LineDirection::Angle(angle)); return Ok(LineDirection::Angle(angle));
} }

View file

@ -29,16 +29,18 @@ pub type TransformOperation = GenericTransformOperation<
LengthOrPercentage, LengthOrPercentage,
LengthOrPercentageOrNumber, LengthOrPercentageOrNumber,
>; >;
/// A specified CSS `transform` /// A specified CSS `transform`
pub type Transform = GenericTransform<TransformOperation>; pub type Transform = GenericTransform<TransformOperation>;
/// The specified value of a CSS `<transform-origin>` /// The specified value of a CSS `<transform-origin>`
pub type TransformOrigin = GenericTransformOrigin<OriginComponent<X>, OriginComponent<Y>, Length>; pub type TransformOrigin = GenericTransformOrigin<OriginComponent<X>, OriginComponent<Y>, Length>;
impl Transform { impl Transform {
/// Internal parse function for deciding if we wish to accept prefixed values or not /// Internal parse function for deciding if we wish to accept prefixed values or not
// Allow unitless zero angle for rotate() and skew() to align with gecko ///
/// `transform` allows unitless zero angles as an exception, see:
/// https://github.com/w3c/csswg-drafts/issues/1162
fn parse_internal<'i, 't>( fn parse_internal<'i, 't>(
context: &ParserContext, context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,