mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
Add parsing support for transform
This commit is contained in:
parent
d6525e030a
commit
544989819d
2 changed files with 219 additions and 4 deletions
|
@ -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,
|
||||
|
|
|
@ -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> {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue