mirror of
https://github.com/servo/servo.git
synced 2025-07-23 07:13:52 +01:00
Derive ToCss for TransformOperation
Now that SequenceWriter<W> does not monomorphise excessively, we can actually type check a derived ToCss without too much type recursion.
This commit is contained in:
parent
cd8f96cc9e
commit
42c8dc983f
2 changed files with 61 additions and 125 deletions
|
@ -30,7 +30,8 @@ pub struct Matrix<T, U = T> {
|
|||
|
||||
#[allow(missing_docs)]
|
||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue)]
|
||||
#[css(comma, function = "matrix3d")]
|
||||
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)]
|
||||
pub struct Matrix3D<T, U = T, V = T> {
|
||||
pub m11: T, pub m12: T, pub m13: T, pub m14: T,
|
||||
pub m21: T, pub m22: T, pub m23: T, pub m24: T,
|
||||
|
@ -191,7 +192,7 @@ impl TimingKeyword {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue)]
|
||||
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)]
|
||||
/// A single operation in the list of a `transform` value
|
||||
pub enum TransformOperation<Angle, Number, Length, Integer, LengthOrNumber, LengthOrPercentage, LoPoNumber> {
|
||||
/// Represents a 2D 2x3 matrix.
|
||||
|
@ -200,31 +201,37 @@ pub enum TransformOperation<Angle, Number, Length, Integer, LengthOrNumber, Leng
|
|||
/// For `moz-transform`.
|
||||
PrefixedMatrix(Matrix<Number, LoPoNumber>),
|
||||
/// Represents a 3D 4x4 matrix.
|
||||
#[allow(missing_docs)]
|
||||
Matrix3D(Matrix3D<Number>),
|
||||
/// Represents a 3D 4x4 matrix with percentage and length values.
|
||||
/// For `moz-transform`.
|
||||
#[allow(missing_docs)]
|
||||
PrefixedMatrix3D(Matrix3D<Number, LoPoNumber, LengthOrNumber>),
|
||||
/// A 2D skew.
|
||||
///
|
||||
/// If the second angle is not provided it is assumed zero.
|
||||
///
|
||||
/// Syntax can be skew(angle) or skew(angle, angle)
|
||||
#[css(comma, function)]
|
||||
Skew(Angle, Option<Angle>),
|
||||
/// skewX(angle)
|
||||
#[css(function = "skewX")]
|
||||
SkewX(Angle),
|
||||
/// skewY(angle)
|
||||
#[css(function = "skewY")]
|
||||
SkewY(Angle),
|
||||
/// translate(x, y) or translate(x)
|
||||
#[css(comma, function)]
|
||||
Translate(LengthOrPercentage, Option<LengthOrPercentage>),
|
||||
/// translateX(x)
|
||||
#[css(function = "translateX")]
|
||||
TranslateX(LengthOrPercentage),
|
||||
/// translateY(y)
|
||||
#[css(function = "translateY")]
|
||||
TranslateY(LengthOrPercentage),
|
||||
/// translateZ(z)
|
||||
#[css(function = "translateZ")]
|
||||
TranslateZ(Length),
|
||||
/// translate3d(x, y, z)
|
||||
#[css(comma, function = "translate3d")]
|
||||
Translate3D(LengthOrPercentage, LengthOrPercentage, Length),
|
||||
/// A 2D scaling factor.
|
||||
///
|
||||
|
@ -234,28 +241,38 @@ pub enum TransformOperation<Angle, Number, Length, Integer, LengthOrNumber, Leng
|
|||
/// Negative values are allowed and flip the element.
|
||||
///
|
||||
/// Syntax can be scale(factor) or scale(factor, factor)
|
||||
#[css(comma, function)]
|
||||
Scale(Number, Option<Number>),
|
||||
/// scaleX(factor)
|
||||
#[css(function = "scaleX")]
|
||||
ScaleX(Number),
|
||||
/// scaleY(factor)
|
||||
#[css(function = "scaleY")]
|
||||
ScaleY(Number),
|
||||
/// scaleZ(factor)
|
||||
#[css(function = "scaleZ")]
|
||||
ScaleZ(Number),
|
||||
/// scale3D(factorX, factorY, factorZ)
|
||||
#[css(comma, function = "scale3d")]
|
||||
Scale3D(Number, Number, Number),
|
||||
/// Describes a 2D Rotation.
|
||||
///
|
||||
/// In a 3D scene `rotate(angle)` is equivalent to `rotateZ(angle)`.
|
||||
#[css(function)]
|
||||
Rotate(Angle),
|
||||
/// Rotation in 3D space around the x-axis.
|
||||
#[css(function = "rotateX")]
|
||||
RotateX(Angle),
|
||||
/// Rotation in 3D space around the y-axis.
|
||||
#[css(function = "rotateY")]
|
||||
RotateY(Angle),
|
||||
/// Rotation in 3D space around the z-axis.
|
||||
#[css(function = "rotateZ")]
|
||||
RotateZ(Angle),
|
||||
/// Rotation in 3D space.
|
||||
///
|
||||
/// Generalization of rotateX, rotateY and rotateZ.
|
||||
#[css(comma, function = "rotate3d")]
|
||||
Rotate3D(Number, Number, Number, Angle),
|
||||
/// Specifies a perspective projection matrix.
|
||||
///
|
||||
|
@ -263,11 +280,14 @@ pub enum TransformOperation<Angle, Number, Length, Integer, LengthOrNumber, Leng
|
|||
/// [§ 13.1. 3D Transform Function](https://drafts.csswg.org/css-transforms-2/#funcdef-perspective).
|
||||
///
|
||||
/// The value must be greater than or equal to zero.
|
||||
#[css(function)]
|
||||
Perspective(Length),
|
||||
/// A intermediate type for interpolation of mismatched transform lists.
|
||||
#[allow(missing_docs)]
|
||||
#[css(comma, function = "interpolatematrix")]
|
||||
InterpolateMatrix {
|
||||
#[compute(ignore_bound)]
|
||||
#[css(ignore_bound)]
|
||||
from_list: Transform<
|
||||
TransformOperation<
|
||||
Angle,
|
||||
|
@ -280,6 +300,7 @@ pub enum TransformOperation<Angle, Number, Length, Integer, LengthOrNumber, Leng
|
|||
>,
|
||||
>,
|
||||
#[compute(ignore_bound)]
|
||||
#[css(ignore_bound)]
|
||||
to_list: Transform<
|
||||
TransformOperation<
|
||||
Angle,
|
||||
|
@ -296,8 +317,10 @@ pub enum TransformOperation<Angle, Number, Length, Integer, LengthOrNumber, Leng
|
|||
},
|
||||
/// A intermediate type for accumulation of mismatched transform lists.
|
||||
#[allow(missing_docs)]
|
||||
#[css(comma, function = "accumulatematrix")]
|
||||
AccumulateMatrix {
|
||||
#[compute(ignore_bound)]
|
||||
#[css(ignore_bound)]
|
||||
from_list: Transform<
|
||||
TransformOperation<
|
||||
Angle,
|
||||
|
@ -310,6 +333,7 @@ pub enum TransformOperation<Angle, Number, Length, Integer, LengthOrNumber, Leng
|
|||
>,
|
||||
>,
|
||||
#[compute(ignore_bound)]
|
||||
#[css(ignore_bound)]
|
||||
to_list: Transform<
|
||||
TransformOperation<
|
||||
Angle,
|
||||
|
@ -541,120 +565,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||
impl<Angle: ToCss + Copy, Number: ToCss + Copy, Length: ToCss,
|
||||
Integer: ToCss + Copy, LengthOrNumber: ToCss, LengthOrPercentage: ToCss, LoPoNumber: ToCss>
|
||||
ToCss for
|
||||
TransformOperation<Angle, Number, Length, Integer, LengthOrNumber, LengthOrPercentage, LoPoNumber> {
|
||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||
where
|
||||
W: Write,
|
||||
{
|
||||
match *self {
|
||||
TransformOperation::Matrix(ref m) => m.to_css(dest),
|
||||
TransformOperation::PrefixedMatrix(ref m) => m.to_css(dest),
|
||||
TransformOperation::Matrix3D(Matrix3D {
|
||||
m11, m12, m13, m14,
|
||||
m21, m22, m23, m24,
|
||||
m31, m32, m33, m34,
|
||||
m41, m42, m43, m44,
|
||||
}) => {
|
||||
serialize_function!(dest, matrix3d(
|
||||
m11, m12, m13, m14,
|
||||
m21, m22, m23, m24,
|
||||
m31, m32, m33, m34,
|
||||
m41, m42, m43, m44,
|
||||
))
|
||||
}
|
||||
TransformOperation::PrefixedMatrix3D(Matrix3D {
|
||||
m11, m12, m13, m14,
|
||||
m21, m22, m23, m24,
|
||||
m31, m32, m33, m34,
|
||||
ref m41, ref m42, ref m43, m44,
|
||||
}) => {
|
||||
serialize_function!(dest, matrix3d(
|
||||
m11, m12, m13, m14,
|
||||
m21, m22, m23, m24,
|
||||
m31, m32, m33, m34,
|
||||
m41, m42, m43, m44,
|
||||
))
|
||||
}
|
||||
TransformOperation::Skew(ax, None) => {
|
||||
serialize_function!(dest, skew(ax))
|
||||
}
|
||||
TransformOperation::Skew(ax, Some(ay)) => {
|
||||
serialize_function!(dest, skew(ax, ay))
|
||||
}
|
||||
TransformOperation::SkewX(angle) => {
|
||||
serialize_function!(dest, skewX(angle))
|
||||
}
|
||||
TransformOperation::SkewY(angle) => {
|
||||
serialize_function!(dest, skewY(angle))
|
||||
}
|
||||
TransformOperation::Translate(ref tx, None) => {
|
||||
serialize_function!(dest, translate(tx))
|
||||
}
|
||||
TransformOperation::Translate(ref tx, Some(ref ty)) => {
|
||||
serialize_function!(dest, translate(tx, ty))
|
||||
}
|
||||
TransformOperation::TranslateX(ref tx) => {
|
||||
serialize_function!(dest, translateX(tx))
|
||||
}
|
||||
TransformOperation::TranslateY(ref ty) => {
|
||||
serialize_function!(dest, translateY(ty))
|
||||
}
|
||||
TransformOperation::TranslateZ(ref tz) => {
|
||||
serialize_function!(dest, translateZ(tz))
|
||||
}
|
||||
TransformOperation::Translate3D(ref tx, ref ty, ref tz) => {
|
||||
serialize_function!(dest, translate3d(tx, ty, tz))
|
||||
}
|
||||
TransformOperation::Scale(factor, None) => {
|
||||
serialize_function!(dest, scale(factor))
|
||||
}
|
||||
TransformOperation::Scale(sx, Some(sy)) => {
|
||||
serialize_function!(dest, scale(sx, sy))
|
||||
}
|
||||
TransformOperation::ScaleX(sx) => {
|
||||
serialize_function!(dest, scaleX(sx))
|
||||
}
|
||||
TransformOperation::ScaleY(sy) => {
|
||||
serialize_function!(dest, scaleY(sy))
|
||||
}
|
||||
TransformOperation::ScaleZ(sz) => {
|
||||
serialize_function!(dest, scaleZ(sz))
|
||||
}
|
||||
TransformOperation::Scale3D(sx, sy, sz) => {
|
||||
serialize_function!(dest, scale3d(sx, sy, sz))
|
||||
}
|
||||
TransformOperation::Rotate(theta) => {
|
||||
serialize_function!(dest, rotate(theta))
|
||||
}
|
||||
TransformOperation::RotateX(theta) => {
|
||||
serialize_function!(dest, rotateX(theta))
|
||||
}
|
||||
TransformOperation::RotateY(theta) => {
|
||||
serialize_function!(dest, rotateY(theta))
|
||||
}
|
||||
TransformOperation::RotateZ(theta) => {
|
||||
serialize_function!(dest, rotateZ(theta))
|
||||
}
|
||||
TransformOperation::Rotate3D(x, y, z, theta) => {
|
||||
serialize_function!(dest, rotate3d(x, y, z, theta))
|
||||
}
|
||||
TransformOperation::Perspective(ref length) => {
|
||||
serialize_function!(dest, perspective(length))
|
||||
}
|
||||
TransformOperation::InterpolateMatrix { ref from_list, ref to_list, progress } => {
|
||||
serialize_function!(dest, interpolatematrix(from_list, to_list, progress))
|
||||
}
|
||||
TransformOperation::AccumulateMatrix { ref from_list, ref to_list, count } => {
|
||||
serialize_function!(dest, accumulatematrix(from_list, to_list, count))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ToCss> ToCss for Transform<T> {
|
||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||
where
|
||||
|
|
|
@ -3,8 +3,9 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use cg;
|
||||
use darling::{Error, FromMetaItem};
|
||||
use quote::Tokens;
|
||||
use syn::DeriveInput;
|
||||
use syn::{self, DeriveInput, Ident};
|
||||
use synstructure;
|
||||
|
||||
pub fn derive(input: DeriveInput) -> Tokens {
|
||||
|
@ -16,13 +17,13 @@ pub fn derive(input: DeriveInput) -> Tokens {
|
|||
let input_attrs = cg::parse_input_attrs::<CssInputAttrs>(&input);
|
||||
let style = synstructure::BindStyle::Ref.into();
|
||||
let match_body = synstructure::each_variant(&input, &style, |bindings, variant| {
|
||||
let mut identifier = cg::to_css_identifier(variant.ident.as_ref());
|
||||
let identifier = cg::to_css_identifier(variant.ident.as_ref());
|
||||
let variant_attrs = cg::parse_variant_attrs::<CssVariantAttrs>(variant);
|
||||
let separator = if variant_attrs.comma { ", " } else { " " };
|
||||
|
||||
if variant_attrs.dimension {
|
||||
assert_eq!(bindings.len(), 1);
|
||||
assert!(!variant_attrs.function, "That makes no sense");
|
||||
assert!(variant_attrs.function.is_none(), "That makes no sense");
|
||||
}
|
||||
|
||||
let mut expr = if !bindings.is_empty() {
|
||||
|
@ -39,7 +40,10 @@ pub fn derive(input: DeriveInput) -> Tokens {
|
|||
};
|
||||
} else {
|
||||
for binding in bindings {
|
||||
where_clause.add_trait_bound(&binding.field.ty);
|
||||
let attrs = cg::parse_field_attrs::<CssFieldAttrs>(&binding.field);
|
||||
if !attrs.ignore_bound {
|
||||
where_clause.add_trait_bound(&binding.field.ty);
|
||||
}
|
||||
expr = quote! {
|
||||
#expr
|
||||
writer.item(#binding)?;
|
||||
|
@ -63,7 +67,8 @@ pub fn derive(input: DeriveInput) -> Tokens {
|
|||
#expr?;
|
||||
::std::fmt::Write::write_str(dest, #identifier)
|
||||
}
|
||||
} else if variant_attrs.function {
|
||||
} else if let Some(function) = variant_attrs.function {
|
||||
let mut identifier = function.name.map_or(identifier, |name| name.to_string());
|
||||
identifier.push_str("(");
|
||||
expr = quote! {
|
||||
::std::fmt::Write::write_str(dest, #identifier)?;
|
||||
|
@ -112,15 +117,36 @@ pub fn derive(input: DeriveInput) -> Tokens {
|
|||
#[derive(Default, FromDeriveInput)]
|
||||
struct CssInputAttrs {
|
||||
derive_debug: bool,
|
||||
function: bool,
|
||||
function: Option<Function>,
|
||||
comma: bool,
|
||||
}
|
||||
|
||||
#[darling(attributes(css), default)]
|
||||
#[derive(Default, FromVariant)]
|
||||
struct CssVariantAttrs {
|
||||
function: bool,
|
||||
function: Option<Function>,
|
||||
iterable: bool,
|
||||
comma: bool,
|
||||
dimension: bool,
|
||||
}
|
||||
|
||||
#[darling(attributes(css), default)]
|
||||
#[derive(Default, FromField)]
|
||||
struct CssFieldAttrs {
|
||||
ignore_bound: bool,
|
||||
}
|
||||
|
||||
struct Function {
|
||||
name: Option<Ident>,
|
||||
}
|
||||
|
||||
impl FromMetaItem for Function {
|
||||
fn from_word() -> Result<Self, Error> {
|
||||
Ok(Self { name: None })
|
||||
}
|
||||
|
||||
fn from_string(name: &str) -> Result<Self, Error> {
|
||||
let name = syn::parse_ident(name).map_err(Error::custom)?;
|
||||
Ok(Self { name: Some(name) })
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue