Add parsing support for transform

This commit is contained in:
Manish Goregaokar 2017-10-03 16:08:32 -07:00
parent d6525e030a
commit 544989819d
No known key found for this signature in database
GPG key ID: 3BBF4D3E2EF79F98
2 changed files with 219 additions and 4 deletions

View file

@ -250,7 +250,7 @@ pub enum TransformOperation<Angle, Number, Length, Integer, LengthOrNumber, Leng
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A value of the `transform` property
pub struct Transform<T>(Vec<T>);
pub struct Transform<T>(pub Vec<T>);
impl<Angle: ToCss + Copy, Number: ToCss + Copy, Length: ToCss,

View file

@ -11,10 +11,11 @@ use style_traits::{ParseError, StyleParseErrorKind};
use values::computed::{Context, LengthOrPercentage as ComputedLengthOrPercentage};
use values::computed::{Percentage as ComputedPercentage, ToComputedValue};
use values::computed::transform::TimingFunction as ComputedTimingFunction;
use values::generics::transform::{StepPosition, TimingFunction as GenericTimingFunction};
use values::generics::transform::{StepPosition, TimingFunction as GenericTimingFunction, Matrix};
use values::generics::transform::{TimingKeyword, TransformOrigin as GenericTransformOrigin};
use values::generics::transform::{Transform as GenericTransform, TransformOperation as GenericTransformOperation};
use values::specified::{Angle, Number, Length, Integer};
use values::generics::transform::Transform as GenericTransform;
use values::generics::transform::TransformOperation as GenericTransformOperation;
use values::specified::{self, Angle, Number, Length, Integer};
use values::specified::{LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrNumber};
use values::specified::position::{Side, X, Y};
@ -27,6 +28,220 @@ pub type Transform = GenericTransform<TransformOperation>;
/// The specified value of a CSS `<transform-origin>`
pub type TransformOrigin = GenericTransformOrigin<OriginComponent<X>, OriginComponent<Y>, 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<Self, ParseError<'i>> {
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 `<transform-origin>`.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)]
pub enum OriginComponent<S> {