diff --git a/components/style/values/generics/transform.rs b/components/style/values/generics/transform.rs index 56d3643404d..116a6d8e228 100644 --- a/components/style/values/generics/transform.rs +++ b/components/style/values/generics/transform.rs @@ -250,7 +250,7 @@ pub enum TransformOperation(Vec); +pub struct Transform(pub Vec); impl; /// The specified value of a CSS `` pub type TransformOrigin = GenericTransformOrigin, OriginComponent, Length>; + +impl Transform { + /// 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 + pub fn parse_internal<'i, 't>( + context: &ParserContext, + input: &mut Parser<'i, 't>, + prefixed: bool, + ) -> Result> { + use style_traits::{Separator, Space}; + + if input.try(|input| input.expect_ident_matching("none")).is_ok() { + return Ok(GenericTransform(Vec::new())) + } + + Ok(GenericTransform(Space::parse(input, |input| { + let function = input.expect_function()?.clone(); + input.parse_nested_block(|input| { + let result = match_ignore_ascii_case! { &function, + "matrix" => { + let a = specified::parse_number(context, input)?; + input.expect_comma()?; + let b = specified::parse_number(context, input)?; + input.expect_comma()?; + let c = specified::parse_number(context, input)?; + input.expect_comma()?; + let d = specified::parse_number(context, input)?; + input.expect_comma()?; + if !prefixed { + // Standard matrix parsing. + let e = specified::parse_number(context, input)?; + input.expect_comma()?; + let f = specified::parse_number(context, input)?; + Ok(GenericTransformOperation::Matrix(Matrix { a, b, c, d, e, f })) + } else { + // Non-standard prefixed matrix parsing for -moz-transform. + let e = LengthOrPercentageOrNumber::parse(context, input)?; + input.expect_comma()?; + let f = LengthOrPercentageOrNumber::parse(context, input)?; + Ok(GenericTransformOperation::PrefixedMatrix(Matrix { a, b, c, d, e, f })) + } + }, + "matrix3d" => { + let m11 = specified::parse_number(context, input)?; + input.expect_comma()?; + let m12 = specified::parse_number(context, input)?; + input.expect_comma()?; + let m13 = specified::parse_number(context, input)?; + input.expect_comma()?; + let m14 = specified::parse_number(context, input)?; + input.expect_comma()?; + let m21 = specified::parse_number(context, input)?; + input.expect_comma()?; + let m22 = specified::parse_number(context, input)?; + input.expect_comma()?; + let m23 = specified::parse_number(context, input)?; + input.expect_comma()?; + let m24 = specified::parse_number(context, input)?; + input.expect_comma()?; + let m31 = specified::parse_number(context, input)?; + input.expect_comma()?; + let m32 = specified::parse_number(context, input)?; + input.expect_comma()?; + let m33 = specified::parse_number(context, input)?; + input.expect_comma()?; + let m34 = specified::parse_number(context, input)?; + input.expect_comma()?; + if !prefixed { + // Standard matrix3d parsing. + let m41 = specified::parse_number(context, input)?; + input.expect_comma()?; + let m42 = specified::parse_number(context, input)?; + input.expect_comma()?; + let m43 = specified::parse_number(context, input)?; + input.expect_comma()?; + let m44 = specified::parse_number(context, input)?; + Ok(GenericTransformOperation::Matrix3D { + m11, m12, m13, m14, + m21, m22, m23, m24, + m31, m32, m33, m34, + m41, m42, m43, m44, + }) + } else { + // Non-standard prefixed matrix parsing for -moz-transform. + let m41 = LengthOrPercentageOrNumber::parse(context, input)?; + input.expect_comma()?; + let m42 = LengthOrPercentageOrNumber::parse(context, input)?; + input.expect_comma()?; + let m43 = LengthOrNumber::parse(context, input)?; + input.expect_comma()?; + let m44 = specified::parse_number(context, input)?; + Ok(GenericTransformOperation::PrefixedMatrix3D { + m11, m12, m13, m14, + m21, m22, m23, m24, + m31, m32, m33, m34, + m41, m42, m43, m44, + }) + } + }, + "translate" => { + let sx = specified::LengthOrPercentage::parse(context, input)?; + if input.try(|input| input.expect_comma()).is_ok() { + let sy = specified::LengthOrPercentage::parse(context, input)?; + Ok(GenericTransformOperation::Translate(sx, Some(sy))) + } else { + Ok(GenericTransformOperation::Translate(sx, None)) + } + }, + "translatex" => { + let tx = specified::LengthOrPercentage::parse(context, input)?; + Ok(GenericTransformOperation::TranslateX(tx)) + }, + "translatey" => { + let ty = specified::LengthOrPercentage::parse(context, input)?; + Ok(GenericTransformOperation::TranslateY(ty)) + }, + "translatez" => { + let tz = specified::Length::parse(context, input)?; + Ok(GenericTransformOperation::TranslateZ(tz)) + }, + "translate3d" => { + let tx = specified::LengthOrPercentage::parse(context, input)?; + input.expect_comma()?; + let ty = specified::LengthOrPercentage::parse(context, input)?; + input.expect_comma()?; + let tz = specified::Length::parse(context, input)?; + Ok(GenericTransformOperation::Translate3D(tx, ty, tz)) + }, + "scale" => { + let sx = specified::parse_number(context, input)?; + if input.try(|input| input.expect_comma()).is_ok() { + let sy = specified::parse_number(context, input)?; + Ok(GenericTransformOperation::Scale(sx, Some(sy))) + } else { + Ok(GenericTransformOperation::Scale(sx, None)) + } + }, + "scalex" => { + let sx = specified::parse_number(context, input)?; + Ok(GenericTransformOperation::ScaleX(sx)) + }, + "scaley" => { + let sy = specified::parse_number(context, input)?; + Ok(GenericTransformOperation::ScaleY(sy)) + }, + "scalez" => { + let sz = specified::parse_number(context, input)?; + Ok(GenericTransformOperation::ScaleZ(sz)) + }, + "scale3d" => { + let sx = specified::parse_number(context, input)?; + input.expect_comma()?; + let sy = specified::parse_number(context, input)?; + input.expect_comma()?; + let sz = specified::parse_number(context, input)?; + Ok(GenericTransformOperation::Scale3D(sx, sy, sz)) + }, + "rotate" => { + let theta = specified::Angle::parse_with_unitless(context, input)?; + Ok(GenericTransformOperation::Rotate(theta)) + }, + "rotatex" => { + let theta = specified::Angle::parse_with_unitless(context, input)?; + Ok(GenericTransformOperation::RotateX(theta)) + }, + "rotatey" => { + let theta = specified::Angle::parse_with_unitless(context, input)?; + Ok(GenericTransformOperation::RotateY(theta)) + }, + "rotatez" => { + let theta = specified::Angle::parse_with_unitless(context, input)?; + Ok(GenericTransformOperation::RotateZ(theta)) + }, + "rotate3d" => { + let ax = specified::parse_number(context, input)?; + input.expect_comma()?; + let ay = specified::parse_number(context, input)?; + input.expect_comma()?; + let az = specified::parse_number(context, input)?; + input.expect_comma()?; + let theta = specified::Angle::parse_with_unitless(context, input)?; + // TODO(gw): Check that the axis can be normalized. + Ok(GenericTransformOperation::Rotate3D(ax, ay, az, theta)) + }, + "skew" => { + let ax = specified::Angle::parse_with_unitless(context, input)?; + if input.try(|input| input.expect_comma()).is_ok() { + let ay = specified::Angle::parse_with_unitless(context, input)?; + Ok(GenericTransformOperation::Skew(ax, Some(ay))) + } else { + Ok(GenericTransformOperation::Skew(ax, None)) + } + }, + "skewx" => { + let theta = specified::Angle::parse_with_unitless(context, input)?; + Ok(GenericTransformOperation::SkewX(theta)) + }, + "skewy" => { + let theta = specified::Angle::parse_with_unitless(context, input)?; + Ok(GenericTransformOperation::SkewY(theta)) + }, + "perspective" => { + let d = specified::Length::parse_non_negative(context, input)?; + Ok(GenericTransformOperation::Perspective(d)) + }, + _ => Err(()), + }; + result + .map_err(|()| StyleParseError::UnexpectedFunction(function.clone()).into()) + }) + })?)) + } +} + /// The specified value of a component of a CSS ``. #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)] pub enum OriginComponent {