mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +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)]
|
#[allow(missing_docs)]
|
||||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
#[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 struct Matrix3D<T, U = T, V = T> {
|
||||||
pub m11: T, pub m12: T, pub m13: T, pub m14: 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,
|
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
|
/// A single operation in the list of a `transform` value
|
||||||
pub enum TransformOperation<Angle, Number, Length, Integer, LengthOrNumber, LengthOrPercentage, LoPoNumber> {
|
pub enum TransformOperation<Angle, Number, Length, Integer, LengthOrNumber, LengthOrPercentage, LoPoNumber> {
|
||||||
/// Represents a 2D 2x3 matrix.
|
/// Represents a 2D 2x3 matrix.
|
||||||
|
@ -200,31 +201,37 @@ pub enum TransformOperation<Angle, Number, Length, Integer, LengthOrNumber, Leng
|
||||||
/// For `moz-transform`.
|
/// For `moz-transform`.
|
||||||
PrefixedMatrix(Matrix<Number, LoPoNumber>),
|
PrefixedMatrix(Matrix<Number, LoPoNumber>),
|
||||||
/// Represents a 3D 4x4 matrix.
|
/// Represents a 3D 4x4 matrix.
|
||||||
#[allow(missing_docs)]
|
|
||||||
Matrix3D(Matrix3D<Number>),
|
Matrix3D(Matrix3D<Number>),
|
||||||
/// Represents a 3D 4x4 matrix with percentage and length values.
|
/// Represents a 3D 4x4 matrix with percentage and length values.
|
||||||
/// For `moz-transform`.
|
/// For `moz-transform`.
|
||||||
#[allow(missing_docs)]
|
|
||||||
PrefixedMatrix3D(Matrix3D<Number, LoPoNumber, LengthOrNumber>),
|
PrefixedMatrix3D(Matrix3D<Number, LoPoNumber, LengthOrNumber>),
|
||||||
/// A 2D skew.
|
/// A 2D skew.
|
||||||
///
|
///
|
||||||
/// If the second angle is not provided it is assumed zero.
|
/// If the second angle is not provided it is assumed zero.
|
||||||
///
|
///
|
||||||
/// Syntax can be skew(angle) or skew(angle, angle)
|
/// Syntax can be skew(angle) or skew(angle, angle)
|
||||||
|
#[css(comma, function)]
|
||||||
Skew(Angle, Option<Angle>),
|
Skew(Angle, Option<Angle>),
|
||||||
/// skewX(angle)
|
/// skewX(angle)
|
||||||
|
#[css(function = "skewX")]
|
||||||
SkewX(Angle),
|
SkewX(Angle),
|
||||||
/// skewY(angle)
|
/// skewY(angle)
|
||||||
|
#[css(function = "skewY")]
|
||||||
SkewY(Angle),
|
SkewY(Angle),
|
||||||
/// translate(x, y) or translate(x)
|
/// translate(x, y) or translate(x)
|
||||||
|
#[css(comma, function)]
|
||||||
Translate(LengthOrPercentage, Option<LengthOrPercentage>),
|
Translate(LengthOrPercentage, Option<LengthOrPercentage>),
|
||||||
/// translateX(x)
|
/// translateX(x)
|
||||||
|
#[css(function = "translateX")]
|
||||||
TranslateX(LengthOrPercentage),
|
TranslateX(LengthOrPercentage),
|
||||||
/// translateY(y)
|
/// translateY(y)
|
||||||
|
#[css(function = "translateY")]
|
||||||
TranslateY(LengthOrPercentage),
|
TranslateY(LengthOrPercentage),
|
||||||
/// translateZ(z)
|
/// translateZ(z)
|
||||||
|
#[css(function = "translateZ")]
|
||||||
TranslateZ(Length),
|
TranslateZ(Length),
|
||||||
/// translate3d(x, y, z)
|
/// translate3d(x, y, z)
|
||||||
|
#[css(comma, function = "translate3d")]
|
||||||
Translate3D(LengthOrPercentage, LengthOrPercentage, Length),
|
Translate3D(LengthOrPercentage, LengthOrPercentage, Length),
|
||||||
/// A 2D scaling factor.
|
/// 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.
|
/// Negative values are allowed and flip the element.
|
||||||
///
|
///
|
||||||
/// Syntax can be scale(factor) or scale(factor, factor)
|
/// Syntax can be scale(factor) or scale(factor, factor)
|
||||||
|
#[css(comma, function)]
|
||||||
Scale(Number, Option<Number>),
|
Scale(Number, Option<Number>),
|
||||||
/// scaleX(factor)
|
/// scaleX(factor)
|
||||||
|
#[css(function = "scaleX")]
|
||||||
ScaleX(Number),
|
ScaleX(Number),
|
||||||
/// scaleY(factor)
|
/// scaleY(factor)
|
||||||
|
#[css(function = "scaleY")]
|
||||||
ScaleY(Number),
|
ScaleY(Number),
|
||||||
/// scaleZ(factor)
|
/// scaleZ(factor)
|
||||||
|
#[css(function = "scaleZ")]
|
||||||
ScaleZ(Number),
|
ScaleZ(Number),
|
||||||
/// scale3D(factorX, factorY, factorZ)
|
/// scale3D(factorX, factorY, factorZ)
|
||||||
|
#[css(comma, function = "scale3d")]
|
||||||
Scale3D(Number, Number, Number),
|
Scale3D(Number, Number, Number),
|
||||||
/// Describes a 2D Rotation.
|
/// Describes a 2D Rotation.
|
||||||
///
|
///
|
||||||
/// In a 3D scene `rotate(angle)` is equivalent to `rotateZ(angle)`.
|
/// In a 3D scene `rotate(angle)` is equivalent to `rotateZ(angle)`.
|
||||||
|
#[css(function)]
|
||||||
Rotate(Angle),
|
Rotate(Angle),
|
||||||
/// Rotation in 3D space around the x-axis.
|
/// Rotation in 3D space around the x-axis.
|
||||||
|
#[css(function = "rotateX")]
|
||||||
RotateX(Angle),
|
RotateX(Angle),
|
||||||
/// Rotation in 3D space around the y-axis.
|
/// Rotation in 3D space around the y-axis.
|
||||||
|
#[css(function = "rotateY")]
|
||||||
RotateY(Angle),
|
RotateY(Angle),
|
||||||
/// Rotation in 3D space around the z-axis.
|
/// Rotation in 3D space around the z-axis.
|
||||||
|
#[css(function = "rotateZ")]
|
||||||
RotateZ(Angle),
|
RotateZ(Angle),
|
||||||
/// Rotation in 3D space.
|
/// Rotation in 3D space.
|
||||||
///
|
///
|
||||||
/// Generalization of rotateX, rotateY and rotateZ.
|
/// Generalization of rotateX, rotateY and rotateZ.
|
||||||
|
#[css(comma, function = "rotate3d")]
|
||||||
Rotate3D(Number, Number, Number, Angle),
|
Rotate3D(Number, Number, Number, Angle),
|
||||||
/// Specifies a perspective projection matrix.
|
/// 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).
|
/// [§ 13.1. 3D Transform Function](https://drafts.csswg.org/css-transforms-2/#funcdef-perspective).
|
||||||
///
|
///
|
||||||
/// The value must be greater than or equal to zero.
|
/// The value must be greater than or equal to zero.
|
||||||
|
#[css(function)]
|
||||||
Perspective(Length),
|
Perspective(Length),
|
||||||
/// A intermediate type for interpolation of mismatched transform lists.
|
/// A intermediate type for interpolation of mismatched transform lists.
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
|
#[css(comma, function = "interpolatematrix")]
|
||||||
InterpolateMatrix {
|
InterpolateMatrix {
|
||||||
#[compute(ignore_bound)]
|
#[compute(ignore_bound)]
|
||||||
|
#[css(ignore_bound)]
|
||||||
from_list: Transform<
|
from_list: Transform<
|
||||||
TransformOperation<
|
TransformOperation<
|
||||||
Angle,
|
Angle,
|
||||||
|
@ -280,6 +300,7 @@ pub enum TransformOperation<Angle, Number, Length, Integer, LengthOrNumber, Leng
|
||||||
>,
|
>,
|
||||||
>,
|
>,
|
||||||
#[compute(ignore_bound)]
|
#[compute(ignore_bound)]
|
||||||
|
#[css(ignore_bound)]
|
||||||
to_list: Transform<
|
to_list: Transform<
|
||||||
TransformOperation<
|
TransformOperation<
|
||||||
Angle,
|
Angle,
|
||||||
|
@ -296,8 +317,10 @@ pub enum TransformOperation<Angle, Number, Length, Integer, LengthOrNumber, Leng
|
||||||
},
|
},
|
||||||
/// A intermediate type for accumulation of mismatched transform lists.
|
/// A intermediate type for accumulation of mismatched transform lists.
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
|
#[css(comma, function = "accumulatematrix")]
|
||||||
AccumulateMatrix {
|
AccumulateMatrix {
|
||||||
#[compute(ignore_bound)]
|
#[compute(ignore_bound)]
|
||||||
|
#[css(ignore_bound)]
|
||||||
from_list: Transform<
|
from_list: Transform<
|
||||||
TransformOperation<
|
TransformOperation<
|
||||||
Angle,
|
Angle,
|
||||||
|
@ -310,6 +333,7 @@ pub enum TransformOperation<Angle, Number, Length, Integer, LengthOrNumber, Leng
|
||||||
>,
|
>,
|
||||||
>,
|
>,
|
||||||
#[compute(ignore_bound)]
|
#[compute(ignore_bound)]
|
||||||
|
#[css(ignore_bound)]
|
||||||
to_list: Transform<
|
to_list: Transform<
|
||||||
TransformOperation<
|
TransformOperation<
|
||||||
Angle,
|
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> {
|
impl<T: ToCss> ToCss for Transform<T> {
|
||||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||||
where
|
where
|
||||||
|
|
|
@ -3,8 +3,9 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use cg;
|
use cg;
|
||||||
|
use darling::{Error, FromMetaItem};
|
||||||
use quote::Tokens;
|
use quote::Tokens;
|
||||||
use syn::DeriveInput;
|
use syn::{self, DeriveInput, Ident};
|
||||||
use synstructure;
|
use synstructure;
|
||||||
|
|
||||||
pub fn derive(input: DeriveInput) -> Tokens {
|
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 input_attrs = cg::parse_input_attrs::<CssInputAttrs>(&input);
|
||||||
let style = synstructure::BindStyle::Ref.into();
|
let style = synstructure::BindStyle::Ref.into();
|
||||||
let match_body = synstructure::each_variant(&input, &style, |bindings, variant| {
|
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 variant_attrs = cg::parse_variant_attrs::<CssVariantAttrs>(variant);
|
||||||
let separator = if variant_attrs.comma { ", " } else { " " };
|
let separator = if variant_attrs.comma { ", " } else { " " };
|
||||||
|
|
||||||
if variant_attrs.dimension {
|
if variant_attrs.dimension {
|
||||||
assert_eq!(bindings.len(), 1);
|
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() {
|
let mut expr = if !bindings.is_empty() {
|
||||||
|
@ -39,7 +40,10 @@ pub fn derive(input: DeriveInput) -> Tokens {
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
for binding in bindings {
|
for binding in bindings {
|
||||||
|
let attrs = cg::parse_field_attrs::<CssFieldAttrs>(&binding.field);
|
||||||
|
if !attrs.ignore_bound {
|
||||||
where_clause.add_trait_bound(&binding.field.ty);
|
where_clause.add_trait_bound(&binding.field.ty);
|
||||||
|
}
|
||||||
expr = quote! {
|
expr = quote! {
|
||||||
#expr
|
#expr
|
||||||
writer.item(#binding)?;
|
writer.item(#binding)?;
|
||||||
|
@ -63,7 +67,8 @@ pub fn derive(input: DeriveInput) -> Tokens {
|
||||||
#expr?;
|
#expr?;
|
||||||
::std::fmt::Write::write_str(dest, #identifier)
|
::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("(");
|
identifier.push_str("(");
|
||||||
expr = quote! {
|
expr = quote! {
|
||||||
::std::fmt::Write::write_str(dest, #identifier)?;
|
::std::fmt::Write::write_str(dest, #identifier)?;
|
||||||
|
@ -112,15 +117,36 @@ pub fn derive(input: DeriveInput) -> Tokens {
|
||||||
#[derive(Default, FromDeriveInput)]
|
#[derive(Default, FromDeriveInput)]
|
||||||
struct CssInputAttrs {
|
struct CssInputAttrs {
|
||||||
derive_debug: bool,
|
derive_debug: bool,
|
||||||
function: bool,
|
function: Option<Function>,
|
||||||
comma: bool,
|
comma: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[darling(attributes(css), default)]
|
#[darling(attributes(css), default)]
|
||||||
#[derive(Default, FromVariant)]
|
#[derive(Default, FromVariant)]
|
||||||
struct CssVariantAttrs {
|
struct CssVariantAttrs {
|
||||||
function: bool,
|
function: Option<Function>,
|
||||||
iterable: bool,
|
iterable: bool,
|
||||||
comma: bool,
|
comma: bool,
|
||||||
dimension: 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