From 13d47ba69a233739cf653b293466e429e94665b4 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Thu, 24 Aug 2017 13:37:39 +0200 Subject: [PATCH 01/18] Remove some garbage code from style_derive --- components/style_derive/cg.rs | 49 ++--------------------------------- 1 file changed, 2 insertions(+), 47 deletions(-) diff --git a/components/style_derive/cg.rs b/components/style_derive/cg.rs index b670da16737..a16fad1bb56 100644 --- a/components/style_derive/cg.rs +++ b/components/style_derive/cg.rs @@ -8,7 +8,7 @@ use std::borrow::Cow; use std::iter; use syn::{AngleBracketedParameterData, Body, DeriveInput, Ident, ImplGenerics}; use syn::{Path, PathParameters, PathSegment, PolyTraitRef, QSelf}; -use syn::{TraitBoundModifier, Ty, TyGenerics, TyParam, TyParamBound, TypeBinding}; +use syn::{TraitBoundModifier, Ty, TyGenerics, TyParam, TyParamBound}; use syn::{Variant, WhereBoundPredicate, WhereClause, WherePredicate}; use syn::visit::{self, Visitor}; use synstructure::{self, BindOpts, BindStyle, BindingInfo}; @@ -60,50 +60,6 @@ pub fn fmap_trait_parts<'a>( (impl_generics, ty_generics, where_clause, output_ty) } -fn fmap_trait_where_predicate( - bounded_ty: Ty, - trait_path: &[&str], - trait_output: Option<(&str, Ty)>, -) -> WherePredicate { - WherePredicate::BoundPredicate(WhereBoundPredicate { - bound_lifetimes: vec![], - bounded_ty, - bounds: vec![TyParamBound::Trait( - PolyTraitRef { - bound_lifetimes: vec![], - trait_ref: fmap_trait_ref(trait_path, trait_output), - }, - TraitBoundModifier::None - )], - }) -} - -fn fmap_trait_ref(path: &[&str], output: Option<(&str, Ty)>) -> Path { - let (name, parent) = path.split_last().unwrap(); - let last_segment = PathSegment { - ident: (*name).into(), - parameters: PathParameters::AngleBracketed( - AngleBracketedParameterData { - bindings: output.into_iter().map(|(param, ty)| { - TypeBinding { ident: param.into(), ty } - }).collect(), - .. Default::default() - } - ) - }; - Path { - global: true, - segments: { - parent - .iter() - .cloned() - .map(Into::into) - .chain(iter::once(last_segment)) - .collect() - }, - } -} - pub fn is_parameterized(ty: &Ty, params: &[TyParam]) -> bool { struct IsParameterized<'a> { params: &'a [TyParam], @@ -166,10 +122,9 @@ pub fn trait_parts<'a>( let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); let mut where_clause = where_clause.clone(); for param in &input.generics.ty_params { - where_clause.predicates.push(fmap_trait_where_predicate( + where_clause.predicates.push(where_predicate( Ty::Path(None, param.ident.clone().into()), trait_path, - None, )); } (impl_generics, ty_generics, where_clause) From 04ad28b564ca34f4c326bca9a0409ec00f61230f Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Fri, 25 Aug 2017 19:58:49 +0200 Subject: [PATCH 02/18] Refactor how we handle trait bounds in style_derive For the traits we derive which methods don't depend on associated types (i.e. all of them but ToAnimatedValue and ToComputedValue), we now add trait bounds for the actual field types directly, instead of bounding the type parameters. --- components/style_derive/animate.rs | 4 +- components/style_derive/cg.rs | 62 +++++++++++++------ .../style_derive/compute_squared_distance.rs | 4 +- .../style_derive/has_viewport_percentage.rs | 5 +- components/style_derive/to_animated_value.rs | 20 +++--- components/style_derive/to_animated_zero.rs | 12 ++-- components/style_derive/to_computed_value.rs | 20 +++--- components/style_derive/to_css.rs | 6 +- 8 files changed, 75 insertions(+), 58 deletions(-) diff --git a/components/style_derive/animate.rs b/components/style_derive/animate.rs index 94d14336087..c95dcdc0e94 100644 --- a/components/style_derive/animate.rs +++ b/components/style_derive/animate.rs @@ -28,9 +28,7 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { let mut computations = quote!(); let iter = result_info.iter().zip(this_info.iter().zip(&other_info)); computations.append_all(iter.map(|(result, (this, other))| { - where_clause.predicates.push( - cg::where_predicate(this.field.ty.clone(), trait_path), - ); + where_clause.add_trait_bound(this.field.ty.clone()); quote! { let #result = ::values::animated::Animate::animate(#this, #other, procedure)?; } diff --git a/components/style_derive/cg.rs b/components/style_derive/cg.rs index a16fad1bb56..ee826dd77ea 100644 --- a/components/style_derive/cg.rs +++ b/components/style_derive/cg.rs @@ -3,16 +3,39 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use darling::FromVariant; -use quote::Tokens; +use quote::{ToTokens, Tokens}; use std::borrow::Cow; +use std::collections::HashSet; use std::iter; -use syn::{AngleBracketedParameterData, Body, DeriveInput, Ident, ImplGenerics}; -use syn::{Path, PathParameters, PathSegment, PolyTraitRef, QSelf}; -use syn::{TraitBoundModifier, Ty, TyGenerics, TyParam, TyParamBound}; -use syn::{Variant, WhereBoundPredicate, WhereClause, WherePredicate}; +use syn::{self, AngleBracketedParameterData, Body, DeriveInput, Ident}; +use syn::{ImplGenerics, Path, PathParameters, PathSegment, PolyTraitRef}; +use syn::{QSelf, TraitBoundModifier, Ty, TyGenerics, TyParam, TyParamBound}; +use syn::{Variant, WhereBoundPredicate, WherePredicate}; use syn::visit::{self, Visitor}; use synstructure::{self, BindOpts, BindStyle, BindingInfo}; +pub struct WhereClause<'input, 'path> { + clause: syn::WhereClause, + params: &'input [TyParam], + trait_path: &'path [&'path str], + bounded_types: HashSet, +} + +impl<'input, 'path> ToTokens for WhereClause<'input, 'path> { + fn to_tokens(&self, tokens: &mut Tokens) { + self.clause.to_tokens(tokens); + } +} + +impl<'input, 'path> WhereClause<'input, 'path> { + pub fn add_trait_bound(&mut self, ty: Ty) { + if is_parameterized(&ty, self.params) && !self.bounded_types.contains(&ty) { + self.bounded_types.insert(ty.clone()); + self.clause.predicates.push(where_predicate(ty, self.trait_path)); + } + } +} + pub fn fmap_match( input: &DeriveInput, bind_style: BindStyle, @@ -35,11 +58,11 @@ where }) } -pub fn fmap_trait_parts<'a>( - input: &'a DeriveInput, - trait_path: &[&str], +pub fn fmap_trait_parts<'input, 'path>( + input: &'input DeriveInput, + trait_path: &'path [&'path str], trait_output: &str, -) -> (ImplGenerics<'a>, TyGenerics<'a>, WhereClause, Path) { +) -> (ImplGenerics<'input>, TyGenerics<'input>, WhereClause<'input, 'path>, Path) { let (impl_generics, ty_generics, where_clause) = trait_parts(input, trait_path); let output_ty = PathSegment { ident: input.ident.clone(), @@ -115,18 +138,17 @@ pub fn ref_pattern<'a>( ) } -pub fn trait_parts<'a>( - input: &'a DeriveInput, - trait_path: &[&str], -) -> (ImplGenerics<'a>, TyGenerics<'a>, WhereClause) { +pub fn trait_parts<'input, 'path>( + input: &'input DeriveInput, + trait_path: &'path [&'path str], +) -> (ImplGenerics<'input>, TyGenerics<'input>, WhereClause<'input, 'path>) { let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - let mut where_clause = where_clause.clone(); - for param in &input.generics.ty_params { - where_clause.predicates.push(where_predicate( - Ty::Path(None, param.ident.clone().into()), - trait_path, - )); - } + let where_clause = WhereClause { + clause: where_clause.clone(), + params: &input.generics.ty_params, + trait_path, + bounded_types: HashSet::new() + }; (impl_generics, ty_generics, where_clause) } diff --git a/components/style_derive/compute_squared_distance.rs b/components/style_derive/compute_squared_distance.rs index 860e568ea88..f3b51f7dc04 100644 --- a/components/style_derive/compute_squared_distance.rs +++ b/components/style_derive/compute_squared_distance.rs @@ -30,9 +30,7 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { } else { let mut sum = quote!(); sum.append_separated(this_info.iter().zip(&other_info).map(|(this, other)| { - where_clause.predicates.push( - cg::where_predicate(this.field.ty.clone(), trait_path), - ); + where_clause.add_trait_bound(this.field.ty.clone()); quote! { ::values::distance::ComputeSquaredDistance::compute_squared_distance(#this, #other)? } diff --git a/components/style_derive/has_viewport_percentage.rs b/components/style_derive/has_viewport_percentage.rs index 5f26d988b8a..07a1eb5b7bb 100644 --- a/components/style_derive/has_viewport_percentage.rs +++ b/components/style_derive/has_viewport_percentage.rs @@ -19,11 +19,10 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { None => return Some(quote!(false)), Some(pair) => pair, }; + where_clause.add_trait_bound(first.field.ty.clone()); let mut expr = quote!(::style_traits::HasViewportPercentage::has_viewport_percentage(#first)); for binding in rest { - where_clause.predicates.push( - cg::where_predicate(binding.field.ty.clone(), trait_path), - ); + where_clause.add_trait_bound(binding.field.ty.clone()); expr = quote!(#expr || ::style_traits::HasViewportPercentage::has_viewport_percentage(#binding)); } Some(expr) diff --git a/components/style_derive/to_animated_value.rs b/components/style_derive/to_animated_value.rs index 5a66ddf65a4..3347116384d 100644 --- a/components/style_derive/to_animated_value.rs +++ b/components/style_derive/to_animated_value.rs @@ -9,18 +9,20 @@ use synstructure::BindStyle; pub fn derive(input: syn::DeriveInput) -> quote::Tokens { let name = &input.ident; - let (impl_generics, ty_generics, where_clause, animated_value_type) = - cg::fmap_trait_parts( - &input, - &["values", "animated", "ToAnimatedValue"], - "AnimatedValue", + let trait_path = &["values", "animated", "ToAnimatedValue"]; + let (impl_generics, ty_generics, mut where_clause, animated_value_type) = + cg::fmap_trait_parts(&input, trait_path, "AnimatedValue"); + for param in &input.generics.ty_params { + where_clause.add_trait_bound( + syn::Ty::Path(None, param.ident.clone().into()), ); + } - let to_body = cg::fmap_match(&input, BindStyle::Move, |field| { - quote!(::values::animated::ToAnimatedValue::to_animated_value(#field)) + let to_body = cg::fmap_match(&input, BindStyle::Move, |binding| { + quote!(::values::animated::ToAnimatedValue::to_animated_value(#binding)) }); - let from_body = cg::fmap_match(&input, BindStyle::Move, |field| { - quote!(::values::animated::ToAnimatedValue::from_animated_value(#field)) + let from_body = cg::fmap_match(&input, BindStyle::Move, |binding| { + quote!(::values::animated::ToAnimatedValue::from_animated_value(#binding)) }); quote! { diff --git a/components/style_derive/to_animated_zero.rs b/components/style_derive/to_animated_zero.rs index d9e67a8a9fe..94b68c7ce9a 100644 --- a/components/style_derive/to_animated_zero.rs +++ b/components/style_derive/to_animated_zero.rs @@ -9,13 +9,13 @@ use synstructure::BindStyle; pub fn derive(input: syn::DeriveInput) -> quote::Tokens { let name = &input.ident; - let (impl_generics, ty_generics, where_clause) = cg::trait_parts( - &input, - &["values", "animated", "ToAnimatedZero"], - ); + let trait_path = &["values", "animated", "ToAnimatedZero"]; + let (impl_generics, ty_generics, mut where_clause) = + cg::trait_parts(&input, trait_path); - let to_body = cg::fmap_match(&input, BindStyle::Ref, |field| { - quote! { ::values::animated::ToAnimatedZero::to_animated_zero(#field)? } + let to_body = cg::fmap_match(&input, BindStyle::Ref, |binding| { + where_clause.add_trait_bound(binding.field.ty.clone()); + quote! { ::values::animated::ToAnimatedZero::to_animated_zero(#binding)? } }); quote! { diff --git a/components/style_derive/to_computed_value.rs b/components/style_derive/to_computed_value.rs index 967f3320a37..ca84265ceeb 100644 --- a/components/style_derive/to_computed_value.rs +++ b/components/style_derive/to_computed_value.rs @@ -9,18 +9,20 @@ use synstructure::BindStyle; pub fn derive(input: syn::DeriveInput) -> quote::Tokens { let name = &input.ident; - let (impl_generics, ty_generics, where_clause, computed_value_type) = - cg::fmap_trait_parts( - &input, - &["values", "computed", "ToComputedValue"], - "ComputedValue", + let trait_path = &["values", "computed", "ToComputedValue"]; + let (impl_generics, ty_generics, mut where_clause, computed_value_type) = + cg::fmap_trait_parts(&input, trait_path, "ComputedValue"); + for param in &input.generics.ty_params { + where_clause.add_trait_bound( + syn::Ty::Path(None, param.ident.clone().into()), ); + } - let to_body = cg::fmap_match(&input, BindStyle::Ref, |field| { - quote!(::values::computed::ToComputedValue::to_computed_value(#field, context)) + let to_body = cg::fmap_match(&input, BindStyle::Ref, |binding| { + quote!(::values::computed::ToComputedValue::to_computed_value(#binding, context)) }); - let from_body = cg::fmap_match(&input, BindStyle::Ref, |field| { - quote!(::values::computed::ToComputedValue::from_computed_value(#field)) + let from_body = cg::fmap_match(&input, BindStyle::Ref, |binding| { + quote!(::values::computed::ToComputedValue::from_computed_value(#binding)) }); quote! { diff --git a/components/style_derive/to_css.rs b/components/style_derive/to_css.rs index 444c42e37da..6dd7567a5fb 100644 --- a/components/style_derive/to_css.rs +++ b/components/style_derive/to_css.rs @@ -21,11 +21,7 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { let mut expr = if !bindings.is_empty() { let mut expr = quote! {}; for binding in bindings { - if cg::is_parameterized(&binding.field.ty, &input.generics.ty_params) { - where_clause.predicates.push( - cg::where_predicate(binding.field.ty.clone(), trait_path), - ); - } + where_clause.add_trait_bound(binding.field.ty.clone()); expr = quote! { #expr writer.item(#binding)?; From dc827c14e1d6be5f5f79d2c7f05167915779bc91 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Fri, 25 Aug 2017 22:27:27 +0200 Subject: [PATCH 03/18] Fix the name of the #[animation] attribute, oops --- components/style_derive/animate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/style_derive/animate.rs b/components/style_derive/animate.rs index c95dcdc0e94..ddc185b5c21 100644 --- a/components/style_derive/animate.rs +++ b/components/style_derive/animate.rs @@ -63,7 +63,7 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { } #[derive(Default, FromVariant)] -#[darling(attributes(animate), default)] +#[darling(attributes(animation), default)] pub struct AnimateAttrs { pub error: bool, } From af560a8fab7a9ead9077e2d2a46ac9ad31e7c107 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Fri, 25 Aug 2017 22:40:24 +0200 Subject: [PATCH 04/18] Support #[animation(error)] in more cases The trait ToAnimatedZero now supports it, and it now applies to things with generics, avoiding the trait bounds for field types of the variant on which it applies. --- .../helpers/animated_properties.mako.rs | 51 +------------------ components/style/values/computed/length.rs | 39 ++------------ components/style_derive/lib.rs | 2 +- components/style_derive/to_animated_zero.rs | 29 ++++++++--- 4 files changed, 31 insertions(+), 90 deletions(-) diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index 2f7aaafc63d..91eda7df3e4 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -48,9 +48,10 @@ use values::animated::effects::TextShadowList as AnimatedTextShadowList; use values::computed::{Angle, BorderCornerRadius, CalcLengthOrPercentage}; use values::computed::{ClipRect, Context, ComputedUrl, ComputedValueAsSpecified}; use values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto}; -use values::computed::{LengthOrPercentageOrNone, MaxLength, MozLength, NonNegativeAu}; +use values::computed::{LengthOrPercentageOrNone, MaxLength, NonNegativeAu}; use values::computed::{NonNegativeNumber, Number, NumberOrPercentage, Percentage}; use values::computed::{PositiveIntegerOrAuto, ToComputedValue}; +#[cfg(feature = "gecko")] use values::computed::MozLength; use values::computed::length::{NonNegativeLengthOrAuto, NonNegativeLengthOrNormal}; use values::computed::length::NonNegativeLengthOrPercentage; use values::distance::{ComputeSquaredDistance, SquaredDistance}; @@ -939,54 +940,6 @@ impl ToAnimatedZero for LengthOrPercentageOrNone { } } -/// https://drafts.csswg.org/css-transitions/#animtype-lpcalc -impl Animate for MozLength { - #[inline] - fn animate(&self, other: &Self, procedure: Procedure) -> Result { - match (self, other) { - ( - &MozLength::LengthOrPercentageOrAuto(ref this), - &MozLength::LengthOrPercentageOrAuto(ref other), - ) => { - Ok(MozLength::LengthOrPercentageOrAuto( - this.animate(other, procedure)?, - )) - } - _ => Err(()), - } - } -} - -impl ToAnimatedZero for MozLength { - #[inline] - fn to_animated_zero(&self) -> Result { - match *self { - MozLength::LengthOrPercentageOrAuto(ref length) => { - Ok(MozLength::LengthOrPercentageOrAuto(length.to_animated_zero()?)) - }, - _ => Err(()) - } - } -} - -/// https://drafts.csswg.org/css-transitions/#animtype-lpcalc -impl Animate for MaxLength { - #[inline] - fn animate(&self, other: &Self, procedure: Procedure) -> Result { - match (self, other) { - ( - &MaxLength::LengthOrPercentageOrNone(ref this), - &MaxLength::LengthOrPercentageOrNone(ref other), - ) => { - Ok(MaxLength::LengthOrPercentageOrNone( - this.animate(other, procedure)?, - )) - }, - _ => Err(()), - } - } -} - impl ToAnimatedZero for MaxLength { #[inline] fn to_animated_zero(&self) -> Result { Err(()) } diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs index a2145d37745..3da3ea9c9a5 100644 --- a/components/style/values/computed/length.rs +++ b/components/style/values/computed/length.rs @@ -695,28 +695,14 @@ pub type NonNegativeLengthOrNumber = Either Result { - match (self, other) { - (&MozLength::LengthOrPercentageOrAuto(ref this), &MozLength::LengthOrPercentageOrAuto(ref other)) => { - this.compute_squared_distance(other) - }, - _ => { - // FIXME(nox): Should this return `Ok(SquaredDistance::Value(1.))` - // when `self` and `other` are the same extremum value? - Err(()) - }, - } - } -} - impl MozLength { /// Returns the `auto` value. pub fn auto() -> Self { @@ -755,28 +741,13 @@ impl ToComputedValue for specified::MozLength { /// See values/specified/length.rs for more details. #[allow(missing_docs)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] -#[derive(Clone, Copy, Debug, PartialEq, ToCss)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, ToCss)] pub enum MaxLength { LengthOrPercentageOrNone(LengthOrPercentageOrNone), + #[animation(error)] ExtremumLength(ExtremumLength), } -impl ComputeSquaredDistance for MaxLength { - #[inline] - fn compute_squared_distance(&self, other: &Self) -> Result { - match (self, other) { - (&MaxLength::LengthOrPercentageOrNone(ref this), &MaxLength::LengthOrPercentageOrNone(ref other)) => { - this.compute_squared_distance(other) - }, - _ => { - // FIXME(nox): Should this return `Ok(SquaredDistance::Value(1.))` - // when `self` and `other` are the same extremum value? - Err(()) - }, - } - } -} - impl MaxLength { /// Returns the `none` value. pub fn none() -> Self { diff --git a/components/style_derive/lib.rs b/components/style_derive/lib.rs index e589759f813..342d9cc4b9b 100644 --- a/components/style_derive/lib.rs +++ b/components/style_derive/lib.rs @@ -43,7 +43,7 @@ pub fn derive_to_animated_value(stream: TokenStream) -> TokenStream { to_animated_value::derive(input).to_string().parse().unwrap() } -#[proc_macro_derive(ToAnimatedZero)] +#[proc_macro_derive(ToAnimatedZero, attributes(animation))] pub fn derive_to_animated_zero(stream: TokenStream) -> TokenStream { let input = syn::parse_derive_input(&stream.to_string()).unwrap(); to_animated_zero::derive(input).to_string().parse().unwrap() diff --git a/components/style_derive/to_animated_zero.rs b/components/style_derive/to_animated_zero.rs index 94b68c7ce9a..50f905ccdc1 100644 --- a/components/style_derive/to_animated_zero.rs +++ b/components/style_derive/to_animated_zero.rs @@ -2,10 +2,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +use animate::AnimateAttrs; use cg; use quote; use syn; -use synstructure::BindStyle; +use synstructure::{self, BindStyle}; pub fn derive(input: syn::DeriveInput) -> quote::Tokens { let name = &input.ident; @@ -13,9 +14,25 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { let (impl_generics, ty_generics, mut where_clause) = cg::trait_parts(&input, trait_path); - let to_body = cg::fmap_match(&input, BindStyle::Ref, |binding| { - where_clause.add_trait_bound(binding.field.ty.clone()); - quote! { ::values::animated::ToAnimatedZero::to_animated_zero(#binding)? } + let bind_opts = BindStyle::Ref.into(); + let to_body = synstructure::each_variant(&input, &bind_opts, |bindings, variant| { + let attrs = cg::parse_variant_attrs::(variant); + if attrs.error { + return Some(quote! { Err(()) }); + } + let name = cg::variant_ctor(&input, variant); + let (mapped, mapped_bindings) = cg::value(&name, variant, "mapped"); + let bindings_pairs = bindings.into_iter().zip(mapped_bindings); + let mut computations = quote!(); + computations.append_all(bindings_pairs.map(|(binding, mapped_binding)| { + where_clause.add_trait_bound(binding.field.ty.clone()); + quote! { + let #mapped_binding = + ::values::animated::ToAnimatedZero::to_animated_zero(#binding)?; + } + })); + computations.append(quote! { Ok(#mapped) }); + Some(computations) }); quote! { @@ -23,9 +40,9 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { #[allow(unused_variables)] #[inline] fn to_animated_zero(&self) -> Result { - Ok(match *self { + match *self { #to_body - }) + } } } } From e49dbc4dfa45defb451ff87484f75cd6d58b4325 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Fri, 25 Aug 2017 23:37:51 +0200 Subject: [PATCH 05/18] Derive Animate for ShapeRadius --- .../style/values/generics/basic_shape.rs | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/components/style/values/generics/basic_shape.rs b/components/style/values/generics/basic_shape.rs index 99de026d706..3de30a30a69 100644 --- a/components/style/values/generics/basic_shape.rs +++ b/components/style/values/generics/basic_shape.rs @@ -94,10 +94,13 @@ pub struct Ellipse { /// https://drafts.csswg.org/css-shapes/#typedef-shape-radius #[allow(missing_docs)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] -#[derive(Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, ToComputedValue, ToCss)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, PartialEq)] +#[derive(ToComputedValue, ToCss)] pub enum ShapeRadius { Length(LengthOrPercentage), + #[animation(error)] ClosestSide, + #[animation(error)] FarthestSide, } @@ -191,20 +194,6 @@ impl ToCss for InsetRect } } -impl Animate for ShapeRadius -where - L: Animate, -{ - fn animate(&self, other: &Self, procedure: Procedure) -> Result { - match (self, other) { - (&ShapeRadius::Length(ref this), &ShapeRadius::Length(ref other)) => { - Ok(ShapeRadius::Length(this.animate(other, procedure)?)) - }, - _ => Err(()), - } - } -} - impl Default for ShapeRadius { #[inline] fn default() -> Self { ShapeRadius::ClosestSide } From eaf2f1ec33f1a130baf62c23fb7f3ea454881504 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Fri, 25 Aug 2017 23:51:12 +0200 Subject: [PATCH 06/18] Introduce #[animation(constant)] for the Animate trait This allows us to handle fields that should be the same during animations. --- components/style/values/animated/effects.rs | 15 -------- .../style/values/generics/basic_shape.rs | 34 +++++-------------- components/style/values/generics/effects.rs | 3 +- components/style_derive/animate.rs | 33 ++++++++++++++++-- components/style_derive/cg.rs | 26 +++++++++----- 5 files changed, 59 insertions(+), 52 deletions(-) diff --git a/components/style/values/animated/effects.rs b/components/style/values/animated/effects.rs index cdde2894549..3fd595cebeb 100644 --- a/components/style/values/animated/effects.rs +++ b/components/style/values/animated/effects.rs @@ -139,21 +139,6 @@ impl ToAnimatedValue for ComputedTextShadowList { } } -// FIXME(nox): This could be derived if we implement Animate for bool. -impl Animate for BoxShadow { - #[inline] - fn animate(&self, other: &Self, procedure: Procedure) -> Result { - if self.inset != other.inset { - return Err(()); - } - Ok(BoxShadow { - base: self.base.animate(&other.base, procedure)?, - spread: self.spread.animate(&other.spread, procedure)?, - inset: self.inset, - }) - } -} - impl ComputeSquaredDistance for BoxShadow { #[inline] fn compute_squared_distance(&self, other: &Self) -> Result { diff --git a/components/style/values/generics/basic_shape.rs b/components/style/values/generics/basic_shape.rs index 3de30a30a69..019ed6599e2 100644 --- a/components/style/values/generics/basic_shape.rs +++ b/components/style/values/generics/basic_shape.rs @@ -44,11 +44,18 @@ add_impls_for_keyword_enum!(ShapeBox); /// A shape source, for some reference box. #[allow(missing_docs)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] -#[derive(Clone, Debug, PartialEq, ToComputedValue, ToCss)] +#[derive(Animate, Clone, Debug, PartialEq, ToComputedValue, ToCss)] pub enum ShapeSource { + #[animation(error)] Url(Url), - Shape(BasicShape, Option), + Shape( + BasicShape, + #[animation(constant)] + Option, + ), + #[animation(error)] Box(ReferenceBox), + #[animation(error)] None, } @@ -126,29 +133,6 @@ define_css_keyword_enum!(FillRule: ); add_impls_for_keyword_enum!(FillRule); -// FIXME(nox): This should be derivable, but we need to implement Animate -// on the T types. -impl Animate for ShapeSource -where - B: Animate, - T: Clone + PartialEq, -{ - fn animate(&self, other: &Self, procedure: Procedure) -> Result { - match (self, other) { - ( - &ShapeSource::Shape(ref this, ref this_box), - &ShapeSource::Shape(ref other, ref other_box), - ) if this_box == other_box => { - Ok(ShapeSource::Shape( - this.animate(other, procedure)?, - this_box.clone(), - )) - }, - _ => Err(()), - } - } -} - // FIXME(nox): Implement ComputeSquaredDistance for T types and stop // using PartialEq here, this will let us derive this impl. impl ComputeSquaredDistance for ShapeSource diff --git a/components/style/values/generics/effects.rs b/components/style/values/generics/effects.rs index 3004c21f9b2..572a211544f 100644 --- a/components/style/values/generics/effects.rs +++ b/components/style/values/generics/effects.rs @@ -11,13 +11,14 @@ use values::specified::url::SpecifiedUrl; /// A generic value for a single `box-shadow`. #[cfg_attr(feature = "servo", derive(HeapSizeOf))] -#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToAnimatedValue)] +#[derive(Animate, Clone, Debug, HasViewportPercentage, PartialEq, ToAnimatedValue)] pub struct BoxShadow { /// The base shadow. pub base: SimpleShadow, /// The spread radius. pub spread: ShapeLength, /// Whether this is an inset box shadow. + #[animation(constant)] pub inset: bool, } diff --git a/components/style_derive/animate.rs b/components/style_derive/animate.rs index ddc185b5c21..6c006aad604 100644 --- a/components/style_derive/animate.rs +++ b/components/style_derive/animate.rs @@ -28,9 +28,30 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { let mut computations = quote!(); let iter = result_info.iter().zip(this_info.iter().zip(&other_info)); computations.append_all(iter.map(|(result, (this, other))| { - where_clause.add_trait_bound(this.field.ty.clone()); - quote! { - let #result = ::values::animated::Animate::animate(#this, #other, procedure)?; + let field_attrs = cg::parse_field_attrs::(&result.field); + if field_attrs.constant { + if cg::is_parameterized(&result.field.ty, where_clause.params) { + where_clause.inner.predicates.push(cg::where_predicate( + result.field.ty.clone(), + &["std", "cmp", "PartialEq"], + )); + where_clause.inner.predicates.push(cg::where_predicate( + result.field.ty.clone(), + &["std", "clone", "Clone"], + )); + } + quote! { + if #this != #other { + return Err(()); + } + let #result = ::std::clone::Clone::clone(#this); + } + } else { + where_clause.add_trait_bound(result.field.ty.clone()); + quote! { + let #result = + ::values::animated::Animate::animate(#this, #other, procedure)?; + } } })); Some(quote! { @@ -67,3 +88,9 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { pub struct AnimateAttrs { pub error: bool, } + +#[derive(Default, FromField)] +#[darling(attributes(animation), default)] +pub struct AnimateFieldAttrs { + pub constant: bool, +} diff --git a/components/style_derive/cg.rs b/components/style_derive/cg.rs index ee826dd77ea..b68b4f95e29 100644 --- a/components/style_derive/cg.rs +++ b/components/style_derive/cg.rs @@ -2,12 +2,12 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use darling::FromVariant; +use darling::{FromField, FromVariant}; use quote::{ToTokens, Tokens}; use std::borrow::Cow; use std::collections::HashSet; use std::iter; -use syn::{self, AngleBracketedParameterData, Body, DeriveInput, Ident}; +use syn::{self, AngleBracketedParameterData, Body, DeriveInput, Field, Ident}; use syn::{ImplGenerics, Path, PathParameters, PathSegment, PolyTraitRef}; use syn::{QSelf, TraitBoundModifier, Ty, TyGenerics, TyParam, TyParamBound}; use syn::{Variant, WhereBoundPredicate, WherePredicate}; @@ -15,15 +15,15 @@ use syn::visit::{self, Visitor}; use synstructure::{self, BindOpts, BindStyle, BindingInfo}; pub struct WhereClause<'input, 'path> { - clause: syn::WhereClause, - params: &'input [TyParam], + pub inner: syn::WhereClause, + pub params: &'input [TyParam], trait_path: &'path [&'path str], bounded_types: HashSet, } impl<'input, 'path> ToTokens for WhereClause<'input, 'path> { fn to_tokens(&self, tokens: &mut Tokens) { - self.clause.to_tokens(tokens); + self.inner.to_tokens(tokens); } } @@ -31,7 +31,7 @@ impl<'input, 'path> WhereClause<'input, 'path> { pub fn add_trait_bound(&mut self, ty: Ty) { if is_parameterized(&ty, self.params) && !self.bounded_types.contains(&ty) { self.bounded_types.insert(ty.clone()); - self.clause.predicates.push(where_predicate(ty, self.trait_path)); + self.inner.predicates.push(where_predicate(ty, self.trait_path)); } } } @@ -116,13 +116,23 @@ where } } +pub fn parse_field_attrs(field: &Field) -> A +where + A: FromField, +{ + match A::from_field(field) { + Ok(attrs) => attrs, + Err(e) => panic!("failed to parse field attributes: {}", e), + } +} + pub fn parse_variant_attrs(variant: &Variant) -> A where A: FromVariant, { match A::from_variant(variant) { Ok(attrs) => attrs, - Err(e) => panic!("failed to parse attributes: {}", e), + Err(e) => panic!("failed to parse variant attributes: {}", e), } } @@ -144,7 +154,7 @@ pub fn trait_parts<'input, 'path>( ) -> (ImplGenerics<'input>, TyGenerics<'input>, WhereClause<'input, 'path>) { let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); let where_clause = WhereClause { - clause: where_clause.clone(), + inner: where_clause.clone(), params: &input.generics.ty_params, trait_path, bounded_types: HashSet::new() From 405e34aa74b99c963ea9d035680dd47ab41673a5 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 26 Aug 2017 00:06:37 +0200 Subject: [PATCH 07/18] Derive a bunch of animation traits for some SVG types --- .../helpers/animated_properties.mako.rs | 71 ------------------- components/style/values/generics/svg.rs | 7 +- 2 files changed, 5 insertions(+), 73 deletions(-) diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index 91eda7df3e4..458814ba17f 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -2384,27 +2384,6 @@ pub type IntermediateSVGPaint = SVGPaint; /// Animated SVGPaintKind pub type IntermediateSVGPaintKind = SVGPaintKind; -impl Animate for IntermediateSVGPaint { - #[inline] - fn animate(&self, other: &Self, procedure: Procedure) -> Result { - Ok(IntermediateSVGPaint { - kind: self.kind.animate(&other.kind, procedure)?, - fallback: self.fallback.animate(&other.fallback, procedure)?, - }) - } -} - -impl ComputeSquaredDistance for IntermediateSVGPaint { - #[inline] - fn compute_squared_distance(&self, other: &Self) -> Result { - // FIXME(nox): This should be derived. - Ok( - self.kind.compute_squared_distance(&other.kind)? + - self.fallback.compute_squared_distance(&other.fallback)?, - ) - } -} - impl ToAnimatedZero for IntermediateSVGPaint { #[inline] fn to_animated_zero(&self) -> Result { @@ -2415,56 +2394,6 @@ impl ToAnimatedZero for IntermediateSVGPaint { } } -impl Animate for IntermediateSVGPaintKind { - #[inline] - fn animate(&self, other: &Self, procedure: Procedure) -> Result { - match (self, other) { - (&SVGPaintKind::Color(ref this), &SVGPaintKind::Color(ref other)) => { - Ok(SVGPaintKind::Color(this.animate(other, procedure)?)) - }, - (&SVGPaintKind::ContextFill, &SVGPaintKind::ContextFill) => Ok(SVGPaintKind::ContextFill), - (&SVGPaintKind::ContextStroke, &SVGPaintKind::ContextStroke) => Ok(SVGPaintKind::ContextStroke), - _ => { - // FIXME: Context values should be interpolable with colors, - // Gecko doesn't implement this behavior either. - Err(()) - } - } - } -} - -impl ComputeSquaredDistance for IntermediateSVGPaintKind { - #[inline] - fn compute_squared_distance(&self, other: &Self) -> Result { - match (self, other) { - (&SVGPaintKind::Color(ref this), &SVGPaintKind::Color(ref other)) => { - this.compute_squared_distance(other) - } - (&SVGPaintKind::None, &SVGPaintKind::None) | - (&SVGPaintKind::ContextFill, &SVGPaintKind::ContextFill) | - (&SVGPaintKind::ContextStroke, &SVGPaintKind::ContextStroke) => { - Ok(SquaredDistance::Value(0.)) - }, - _ => Err(()) - } - } -} - -impl ToAnimatedZero for IntermediateSVGPaintKind { - #[inline] - fn to_animated_zero(&self) -> Result { - match *self { - SVGPaintKind::Color(ref color) => { - Ok(SVGPaintKind::Color(color.to_animated_zero()?)) - }, - SVGPaintKind::None | - SVGPaintKind::ContextFill | - SVGPaintKind::ContextStroke => Ok(self.clone()), - _ => Err(()), - } - } -} - impl From for NumberOrPercentage { fn from(lop: NonNegativeLengthOrPercentage) -> NumberOrPercentage { lop.0.into() diff --git a/components/style/values/generics/svg.rs b/components/style/values/generics/svg.rs index bc3cb5fda18..87b0a74bc23 100644 --- a/components/style/values/generics/svg.rs +++ b/components/style/values/generics/svg.rs @@ -16,7 +16,8 @@ use values::distance::{ComputeSquaredDistance, SquaredDistance}; /// /// https://www.w3.org/TR/SVG2/painting.html#SpecifyingPaint #[cfg_attr(feature = "servo", derive(HeapSizeOf))] -#[derive(Clone, Debug, PartialEq, ToAnimatedValue, ToComputedValue, ToCss)] +#[derive(Animate, Clone, ComputeSquaredDistance, Debug, PartialEq)] +#[derive(ToAnimatedValue, ToComputedValue, ToCss)] pub struct SVGPaint { /// The paint source pub kind: SVGPaintKind, @@ -30,13 +31,15 @@ pub struct SVGPaint { /// to have a fallback, Gecko lets the context /// properties have a fallback as well. #[cfg_attr(feature = "servo", derive(HeapSizeOf))] -#[derive(Clone, Debug, PartialEq, ToAnimatedValue, ToComputedValue, ToCss)] +#[derive(Animate, Clone, ComputeSquaredDistance, Debug, PartialEq)] +#[derive(ToAnimatedValue, ToAnimatedZero, ToComputedValue, ToCss)] pub enum SVGPaintKind { /// `none` None, /// `` Color(ColorType), /// `url(...)` + #[animation(error)] PaintServer(UrlPaintServer), /// `context-fill` ContextFill, From 8101887d31c69d47e30bb31c09bde0560aace5e8 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 26 Aug 2017 00:07:02 +0200 Subject: [PATCH 08/18] Support #[animation(constant)] when deriving ToAnimatedZero --- components/style/values/animated/effects.rs | 11 ---------- components/style/values/computed/length.rs | 17 +++------------ components/style/values/generics/effects.rs | 3 ++- components/style_derive/to_animated_zero.rs | 23 ++++++++++++++++----- 4 files changed, 23 insertions(+), 31 deletions(-) diff --git a/components/style/values/animated/effects.rs b/components/style/values/animated/effects.rs index 3fd595cebeb..eb03bd9565b 100644 --- a/components/style/values/animated/effects.rs +++ b/components/style/values/animated/effects.rs @@ -152,17 +152,6 @@ impl ComputeSquaredDistance for BoxShadow { } } -impl ToAnimatedZero for BoxShadow { - #[inline] - fn to_animated_zero(&self) -> Result { - Ok(BoxShadow { - base: self.base.to_animated_zero()?, - spread: self.spread.to_animated_zero()?, - inset: self.inset, - }) - } -} - impl ToAnimatedValue for ComputedFilterList { type AnimatedValue = FilterList; diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs index 3da3ea9c9a5..a6600a806a2 100644 --- a/components/style/values/computed/length.rs +++ b/components/style/values/computed/length.rs @@ -11,7 +11,6 @@ use style_traits::ToCss; use style_traits::values::specified::AllowedLengthType; use super::{Number, ToComputedValue, Context, Percentage}; use values::{Auto, CSSFloat, Either, ExtremumLength, None_, Normal, specified}; -use values::animated::ToAnimatedZero; use values::computed::{NonNegativeAu, NonNegativeNumber}; use values::distance::{ComputeSquaredDistance, SquaredDistance}; use values::generics::NonNegative; @@ -64,26 +63,16 @@ impl ToComputedValue for specified::Length { } } -#[derive(Clone, Copy, Debug, PartialEq)] -#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[allow(missing_docs)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[derive(Clone, Copy, Debug, PartialEq, ToAnimatedZero)] pub struct CalcLengthOrPercentage { + #[animation(constant)] pub clamping_mode: AllowedLengthType, length: Au, pub percentage: Option, } -impl ToAnimatedZero for CalcLengthOrPercentage { - #[inline] - fn to_animated_zero(&self) -> Result { - Ok(CalcLengthOrPercentage { - clamping_mode: self.clamping_mode, - length: self.length.to_animated_zero()?, - percentage: self.percentage.to_animated_zero()?, - }) - } -} - impl ComputeSquaredDistance for CalcLengthOrPercentage { #[inline] fn compute_squared_distance(&self, other: &Self) -> Result { diff --git a/components/style/values/generics/effects.rs b/components/style/values/generics/effects.rs index 572a211544f..5d95ae19a8f 100644 --- a/components/style/values/generics/effects.rs +++ b/components/style/values/generics/effects.rs @@ -11,7 +11,8 @@ use values::specified::url::SpecifiedUrl; /// A generic value for a single `box-shadow`. #[cfg_attr(feature = "servo", derive(HeapSizeOf))] -#[derive(Animate, Clone, Debug, HasViewportPercentage, PartialEq, ToAnimatedValue)] +#[derive(Animate, Clone, Debug, HasViewportPercentage, PartialEq)] +#[derive(ToAnimatedValue, ToAnimatedZero)] pub struct BoxShadow { /// The base shadow. pub base: SimpleShadow, diff --git a/components/style_derive/to_animated_zero.rs b/components/style_derive/to_animated_zero.rs index 50f905ccdc1..2c76935c6dd 100644 --- a/components/style_derive/to_animated_zero.rs +++ b/components/style_derive/to_animated_zero.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use animate::AnimateAttrs; +use animate::{AnimateAttrs, AnimateFieldAttrs}; use cg; use quote; use syn; @@ -25,10 +25,23 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { let bindings_pairs = bindings.into_iter().zip(mapped_bindings); let mut computations = quote!(); computations.append_all(bindings_pairs.map(|(binding, mapped_binding)| { - where_clause.add_trait_bound(binding.field.ty.clone()); - quote! { - let #mapped_binding = - ::values::animated::ToAnimatedZero::to_animated_zero(#binding)?; + let field_attrs = cg::parse_field_attrs::(&binding.field); + if field_attrs.constant { + if cg::is_parameterized(&binding.field.ty, where_clause.params) { + where_clause.inner.predicates.push(cg::where_predicate( + binding.field.ty.clone(), + &["std", "clone", "Clone"], + )); + } + quote! { + let #mapped_binding = ::std::clone::Clone::clone(#binding); + } + } else { + where_clause.add_trait_bound(binding.field.ty.clone()); + quote! { + let #mapped_binding = + ::values::animated::ToAnimatedZero::to_animated_zero(#binding)?; + } } })); computations.append(quote! { Ok(#mapped) }); From efc852f6e3d72d3cacde32605fb0b7afa7b6ebcd Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 26 Aug 2017 12:40:28 +0200 Subject: [PATCH 09/18] Improve handling of trait bounds when deriving fmap-like traits --- components/style/values/computed/image.rs | 30 --- components/style/values/generics/grid.rs | 37 +-- components/style/values/generics/image.rs | 2 +- components/style/values/specified/grid.rs | 24 -- components/style_derive/animate.rs | 6 +- components/style_derive/cg.rs | 227 ++++++++++++++++-- .../style_derive/compute_squared_distance.rs | 2 +- .../style_derive/has_viewport_percentage.rs | 4 +- components/style_derive/to_animated_value.rs | 6 +- components/style_derive/to_animated_zero.rs | 5 +- components/style_derive/to_computed_value.rs | 20 +- components/style_derive/to_css.rs | 2 +- 12 files changed, 229 insertions(+), 136 deletions(-) diff --git a/components/style/values/computed/image.rs b/components/style/values/computed/image.rs index a4a51b7bae6..f188adf3f7d 100644 --- a/components/style/values/computed/image.rs +++ b/components/style/values/computed/image.rs @@ -203,33 +203,3 @@ impl ToComputedValue for SpecifiedGradient { } } } - -impl ToComputedValue for SpecifiedGradientKind { - type ComputedValue = GradientKind; - - fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { - match self { - &GenericGradientKind::Linear(ref line_direction) => { - GenericGradientKind::Linear(line_direction.to_computed_value(context)) - }, - &GenericGradientKind::Radial(ref ending_shape, ref position, ref angle) => { - GenericGradientKind::Radial(ending_shape.to_computed_value(context), - position.to_computed_value(context), - angle.map(|angle| angle.to_computed_value(context))) - } - } - } - - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - match *computed { - GenericGradientKind::Linear(line_direction) => { - GenericGradientKind::Linear(SpecifiedLineDirection::from_computed_value(&line_direction)) - }, - GenericGradientKind::Radial(ending_shape, position, angle) => { - GenericGradientKind::Radial(ToComputedValue::from_computed_value(&ending_shape), - ToComputedValue::from_computed_value(&position), - angle.map(|angle| ToComputedValue::from_computed_value(&angle))) - } - } - } -} diff --git a/components/style/values/generics/grid.rs b/components/style/values/generics/grid.rs index 91b1e922d14..fba3d747fa8 100644 --- a/components/style/values/generics/grid.rs +++ b/components/style/values/generics/grid.rs @@ -204,7 +204,7 @@ impl ToComputedValue for TrackBreadth { /// /// https://drafts.csswg.org/css-grid/#typedef-track-size #[cfg_attr(feature = "servo", derive(HeapSizeOf))] -#[derive(Clone, Debug, HasViewportPercentage, PartialEq)] +#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToComputedValue)] pub enum TrackSize { /// A flexible `` Breadth(TrackBreadth), @@ -286,39 +286,6 @@ impl ToCss for TrackSize { } } -impl ToComputedValue for TrackSize { - type ComputedValue = TrackSize; - - #[inline] - fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { - match *self { - TrackSize::Breadth(ref b) => match *b { - // outside `minmax()` expands to `mimmax(auto, )` - // https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-flex - TrackBreadth::Flex(f) => - TrackSize::Minmax(TrackBreadth::Keyword(TrackKeyword::Auto), TrackBreadth::Flex(f)), - _ => TrackSize::Breadth(b.to_computed_value(context)), - }, - TrackSize::Minmax(ref b_1, ref b_2) => - TrackSize::Minmax(b_1.to_computed_value(context), b_2.to_computed_value(context)), - TrackSize::FitContent(ref lop) => TrackSize::FitContent(lop.to_computed_value(context)), - } - } - - #[inline] - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - match *computed { - TrackSize::Breadth(ref b) => - TrackSize::Breadth(ToComputedValue::from_computed_value(b)), - TrackSize::Minmax(ref b_1, ref b_2) => - TrackSize::Minmax(ToComputedValue::from_computed_value(b_1), - ToComputedValue::from_computed_value(b_2)), - TrackSize::FitContent(ref lop) => - TrackSize::FitContent(ToComputedValue::from_computed_value(lop)), - } - } -} - /// Helper function for serializing identifiers with a prefix and suffix, used /// for serializing (in grid). pub fn concat_serialize_idents(prefix: &str, suffix: &str, @@ -698,8 +665,8 @@ no_viewport_percentage!(LineNameList); /// Variants for ` | ` /// Subgrid deferred to Level 2 spec due to lack of implementation. /// But it's implemented in gecko, so we have to as well. -#[derive(Clone, Debug, PartialEq, ToCss)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[derive(Clone, Debug, PartialEq, ToComputedValue, ToCss)] pub enum GridTemplateComponent { /// `none` value. None, diff --git a/components/style/values/generics/image.rs b/components/style/values/generics/image.rs index 867364e3df3..bc8f038ffb2 100644 --- a/components/style/values/generics/image.rs +++ b/components/style/values/generics/image.rs @@ -61,8 +61,8 @@ pub enum CompatMode { } /// A gradient kind. -#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)] pub enum GradientKind { /// A linear gradient. Linear(LineDirection), diff --git a/components/style/values/specified/grid.rs b/components/style/values/specified/grid.rs index 92a442a1cf0..6499bbcb49b 100644 --- a/components/style/values/specified/grid.rs +++ b/components/style/values/specified/grid.rs @@ -354,27 +354,3 @@ impl HasViewportPercentage for GridTemplateComponent { } } } - -impl ToComputedValue for GridTemplateComponent { - type ComputedValue = GridTemplateComponent; - - #[inline] - fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { - match *self { - GridTemplateComponent::None => GridTemplateComponent::None, - GridTemplateComponent::TrackList(ref l) => GridTemplateComponent::TrackList(l.to_computed_value(context)), - GridTemplateComponent::Subgrid(ref n) => GridTemplateComponent::Subgrid(n.to_computed_value(context)), - } - } - - #[inline] - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - match *computed { - GridTemplateComponent::None => GridTemplateComponent::None, - GridTemplateComponent::TrackList(ref l) => - GridTemplateComponent::TrackList(ToComputedValue::from_computed_value(l)), - GridTemplateComponent::Subgrid(ref n) => - GridTemplateComponent::Subgrid(ToComputedValue::from_computed_value(n)), - } - } -} diff --git a/components/style_derive/animate.rs b/components/style_derive/animate.rs index 6c006aad604..9153b7792e7 100644 --- a/components/style_derive/animate.rs +++ b/components/style_derive/animate.rs @@ -30,14 +30,16 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { computations.append_all(iter.map(|(result, (this, other))| { let field_attrs = cg::parse_field_attrs::(&result.field); if field_attrs.constant { - if cg::is_parameterized(&result.field.ty, where_clause.params) { + if cg::is_parameterized(&result.field.ty, where_clause.params, None) { where_clause.inner.predicates.push(cg::where_predicate( result.field.ty.clone(), &["std", "cmp", "PartialEq"], + None, )); where_clause.inner.predicates.push(cg::where_predicate( result.field.ty.clone(), &["std", "clone", "Clone"], + None, )); } quote! { @@ -47,7 +49,7 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { let #result = ::std::clone::Clone::clone(#this); } } else { - where_clause.add_trait_bound(result.field.ty.clone()); + where_clause.add_trait_bound(&result.field.ty); quote! { let #result = ::values::animated::Animate::animate(#this, #other, procedure)?; diff --git a/components/style_derive/cg.rs b/components/style_derive/cg.rs index b68b4f95e29..89748939c11 100644 --- a/components/style_derive/cg.rs +++ b/components/style_derive/cg.rs @@ -10,7 +10,7 @@ use std::iter; use syn::{self, AngleBracketedParameterData, Body, DeriveInput, Field, Ident}; use syn::{ImplGenerics, Path, PathParameters, PathSegment, PolyTraitRef}; use syn::{QSelf, TraitBoundModifier, Ty, TyGenerics, TyParam, TyParamBound}; -use syn::{Variant, WhereBoundPredicate, WherePredicate}; +use syn::{TypeBinding, Variant, WhereBoundPredicate, WherePredicate}; use syn::visit::{self, Visitor}; use synstructure::{self, BindOpts, BindStyle, BindingInfo}; @@ -18,6 +18,7 @@ pub struct WhereClause<'input, 'path> { pub inner: syn::WhereClause, pub params: &'input [TyParam], trait_path: &'path [&'path str], + trait_output: Option<&'path str>, bounded_types: HashSet, } @@ -28,10 +29,55 @@ impl<'input, 'path> ToTokens for WhereClause<'input, 'path> { } impl<'input, 'path> WhereClause<'input, 'path> { - pub fn add_trait_bound(&mut self, ty: Ty) { - if is_parameterized(&ty, self.params) && !self.bounded_types.contains(&ty) { - self.bounded_types.insert(ty.clone()); - self.inner.predicates.push(where_predicate(ty, self.trait_path)); + pub fn add_trait_bound(&mut self, ty: &Ty) { + let trait_path = self.trait_path; + let params = self.params; + let mut found = self.trait_output.map(|_| HashSet::new()); + if self.bounded_types.contains(&ty) { + return; + } + if !is_parameterized(&ty, params, found.as_mut()) { + return; + } + self.bounded_types.insert(ty.clone()); + + let output = if let Some(output) = self.trait_output { + output + } else { + self.inner.predicates.push(where_predicate(ty.clone(), trait_path, None)); + return; + }; + + if let Ty::Path(None, ref path) = *ty { + if path_to_ident(path).is_some() { + self.inner.predicates.push(where_predicate(ty.clone(), trait_path, None)); + return; + } + } + + let output_type = map_type_params(ty, params, &mut |ident| { + let ty = Ty::Path(None, ident.clone().into()); + fmap_output_type(ty, trait_path, output) + }); + + let pred = where_predicate( + ty.clone(), + trait_path, + Some((output, output_type)), + ); + + self.inner.predicates.push(pred); + + if let Some(found) = found { + for ident in found { + let ty = Ty::Path(None, ident.into()); + if !self.bounded_types.contains(&ty) { + self.bounded_types.insert(ty.clone()); + self.inner.predicates.push( + where_predicate(ty, trait_path, None), + ); + }; + } } } } @@ -58,23 +104,36 @@ where }) } +fn fmap_output_type( + ty: Ty, + trait_path: &[&str], + trait_output: &str, +) -> Ty { + Ty::Path( + Some(QSelf { + ty: Box::new(ty), + position: trait_path.len(), + }), + path(trait_path.iter().chain(iter::once(&trait_output))), + ) +} + pub fn fmap_trait_parts<'input, 'path>( input: &'input DeriveInput, trait_path: &'path [&'path str], - trait_output: &str, + trait_output: &'path str, ) -> (ImplGenerics<'input>, TyGenerics<'input>, WhereClause<'input, 'path>, Path) { - let (impl_generics, ty_generics, where_clause) = trait_parts(input, trait_path); + let (impl_generics, ty_generics, mut where_clause) = trait_parts(input, trait_path); + where_clause.trait_output = Some(trait_output); let output_ty = PathSegment { ident: input.ident.clone(), parameters: PathParameters::AngleBracketed(AngleBracketedParameterData { lifetimes: input.generics.lifetimes.iter().map(|l| l.lifetime.clone()).collect(), types: input.generics.ty_params.iter().map(|ty| { - Ty::Path( - Some(QSelf { - ty: Box::new(Ty::Path(None, ty.ident.clone().into())), - position: trait_path.len(), - }), - path(trait_path.iter().chain(iter::once(&trait_output))), + fmap_output_type( + Ty::Path(None, ty.ident.clone().into()), + trait_path, + trait_output, ) }).collect(), .. Default::default() @@ -83,28 +142,106 @@ pub fn fmap_trait_parts<'input, 'path>( (impl_generics, ty_generics, where_clause, output_ty) } -pub fn is_parameterized(ty: &Ty, params: &[TyParam]) -> bool { - struct IsParameterized<'a> { +pub fn is_parameterized( + ty: &Ty, + params: &[TyParam], + found: Option<&mut HashSet>, +) -> bool { + struct IsParameterized<'a, 'b> { params: &'a [TyParam], has_free: bool, + found: Option<&'b mut HashSet>, } - impl<'a> Visitor for IsParameterized<'a> { + impl<'a, 'b> Visitor for IsParameterized<'a, 'b> { fn visit_path(&mut self, path: &Path) { - if !path.global && path.segments.len() == 1 { - if self.params.iter().any(|param| param.ident == path.segments[0].ident) { + if let Some(ident) = path_to_ident(path) { + if self.params.iter().any(|param| param.ident == ident) { self.has_free = true; + if let Some(ref mut found) = self.found { + found.insert(ident.clone()); + } } } visit::walk_path(self, path); } } - let mut visitor = IsParameterized { params: params, has_free: false }; + let mut visitor = IsParameterized { params, has_free: false, found }; visitor.visit_ty(ty); visitor.has_free } +pub fn map_type_params(ty: &Ty, params: &[TyParam], f: &mut F) -> Ty +where + F: FnMut(&Ident) -> Ty, +{ + match *ty { + Ty::Slice(ref ty) => Ty::Slice(Box::new(map_type_params(ty, params, f))), + Ty::Array(ref ty, ref expr) => { + Ty::Array(Box::new(map_type_params(ty, params, f)), expr.clone()) + }, + Ty::Never => Ty::Never, + Ty::Tup(ref items) => { + Ty::Tup(items.iter().map(|ty| map_type_params(ty, params, f)).collect()) + }, + Ty::Path(None, ref path) => { + if let Some(ident) = path_to_ident(path) { + if params.iter().any(|param| param.ident == ident) { + return f(ident); + } + } + Ty::Path(None, map_type_params_in_path(path, params, f)) + } + Ty::Path(ref qself, ref path) => { + Ty::Path( + qself.as_ref().map(|qself| { + QSelf { + ty: Box::new(map_type_params(&qself.ty, params, f)), + position: qself.position, + } + }), + map_type_params_in_path(path, params, f), + ) + }, + Ty::Paren(ref ty) => Ty::Paren(Box::new(map_type_params(ty, params, f))), + ref ty => panic!("type {:?} cannot be mapped yet", ty), + } +} + +fn map_type_params_in_path(path: &Path, params: &[TyParam], f: &mut F) -> Path +where + F: FnMut(&Ident) -> Ty, +{ + Path { + global: path.global, + segments: path.segments.iter().map(|segment| { + PathSegment { + ident: segment.ident.clone(), + parameters: match segment.parameters { + PathParameters::AngleBracketed(ref data) => { + PathParameters::AngleBracketed(AngleBracketedParameterData { + lifetimes: data.lifetimes.clone(), + types: data.types.iter().map(|ty| { + map_type_params(ty, params, f) + }).collect(), + bindings: data.bindings.iter().map(|binding| { + TypeBinding { + ident: binding.ident.clone(), + ty: map_type_params(&binding.ty, params, f), + } + }).collect(), + }) + }, + ref parameters => { + panic!("parameters {:?} cannot be mapped yet", parameters) + }, + }, + } + }).collect(), + } +} + pub fn path(segments: S) -> Path where S: IntoIterator, @@ -116,6 +253,19 @@ where } } +fn path_to_ident(path: &Path) -> Option<&Ident> { + match *path { + Path { global: false, ref segments } if segments.len() == 1 => { + if segments[0].parameters.is_empty() { + Some(&segments[0].ident) + } else { + None + } + }, + _ => None, + } +} + pub fn parse_field_attrs(field: &Field) -> A where A: FromField, @@ -157,11 +307,38 @@ pub fn trait_parts<'input, 'path>( inner: where_clause.clone(), params: &input.generics.ty_params, trait_path, + trait_output: None, bounded_types: HashSet::new() }; (impl_generics, ty_generics, where_clause) } +fn trait_ref(path: &[&str], output: Option<(&str, Ty)>) -> Path { + let (name, parent) = path.split_last().unwrap(); + let last_segment = PathSegment { + ident: (*name).into(), + parameters: PathParameters::AngleBracketed( + AngleBracketedParameterData { + bindings: output.into_iter().map(|(param, ty)| { + TypeBinding { ident: param.into(), ty } + }).collect(), + .. Default::default() + } + ) + }; + Path { + global: true, + segments: { + parent + .iter() + .cloned() + .map(Into::into) + .chain(iter::once(last_segment)) + .collect() + }, + } +} + pub fn value<'a>( name: &Ident, variant: &'a Variant, @@ -202,16 +379,20 @@ pub fn variants(input: &DeriveInput) -> Cow<[Variant]> { } } -pub fn where_predicate(ty: Ty, segments: &[&str]) -> WherePredicate { +pub fn where_predicate( + bounded_ty: Ty, + trait_path: &[&str], + trait_output: Option<(&str, Ty)>, +) -> WherePredicate { WherePredicate::BoundPredicate(WhereBoundPredicate { bound_lifetimes: vec![], - bounded_ty: ty, + bounded_ty, bounds: vec![TyParamBound::Trait( PolyTraitRef { bound_lifetimes: vec![], - trait_ref: path(segments), + trait_ref: trait_ref(trait_path, trait_output), }, - TraitBoundModifier::None, + TraitBoundModifier::None )], }) } diff --git a/components/style_derive/compute_squared_distance.rs b/components/style_derive/compute_squared_distance.rs index f3b51f7dc04..9d92c18fcce 100644 --- a/components/style_derive/compute_squared_distance.rs +++ b/components/style_derive/compute_squared_distance.rs @@ -30,7 +30,7 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { } else { let mut sum = quote!(); sum.append_separated(this_info.iter().zip(&other_info).map(|(this, other)| { - where_clause.add_trait_bound(this.field.ty.clone()); + where_clause.add_trait_bound(&this.field.ty); quote! { ::values::distance::ComputeSquaredDistance::compute_squared_distance(#this, #other)? } diff --git a/components/style_derive/has_viewport_percentage.rs b/components/style_derive/has_viewport_percentage.rs index 07a1eb5b7bb..18856576fb8 100644 --- a/components/style_derive/has_viewport_percentage.rs +++ b/components/style_derive/has_viewport_percentage.rs @@ -19,10 +19,10 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { None => return Some(quote!(false)), Some(pair) => pair, }; - where_clause.add_trait_bound(first.field.ty.clone()); + where_clause.add_trait_bound(&first.field.ty); let mut expr = quote!(::style_traits::HasViewportPercentage::has_viewport_percentage(#first)); for binding in rest { - where_clause.add_trait_bound(binding.field.ty.clone()); + where_clause.add_trait_bound(&binding.field.ty); expr = quote!(#expr || ::style_traits::HasViewportPercentage::has_viewport_percentage(#binding)); } Some(expr) diff --git a/components/style_derive/to_animated_value.rs b/components/style_derive/to_animated_value.rs index 3347116384d..7865ba597e9 100644 --- a/components/style_derive/to_animated_value.rs +++ b/components/style_derive/to_animated_value.rs @@ -12,13 +12,9 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { let trait_path = &["values", "animated", "ToAnimatedValue"]; let (impl_generics, ty_generics, mut where_clause, animated_value_type) = cg::fmap_trait_parts(&input, trait_path, "AnimatedValue"); - for param in &input.generics.ty_params { - where_clause.add_trait_bound( - syn::Ty::Path(None, param.ident.clone().into()), - ); - } let to_body = cg::fmap_match(&input, BindStyle::Move, |binding| { + where_clause.add_trait_bound(&binding.field.ty); quote!(::values::animated::ToAnimatedValue::to_animated_value(#binding)) }); let from_body = cg::fmap_match(&input, BindStyle::Move, |binding| { diff --git a/components/style_derive/to_animated_zero.rs b/components/style_derive/to_animated_zero.rs index 2c76935c6dd..f733bfa4ed5 100644 --- a/components/style_derive/to_animated_zero.rs +++ b/components/style_derive/to_animated_zero.rs @@ -27,17 +27,18 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { computations.append_all(bindings_pairs.map(|(binding, mapped_binding)| { let field_attrs = cg::parse_field_attrs::(&binding.field); if field_attrs.constant { - if cg::is_parameterized(&binding.field.ty, where_clause.params) { + if cg::is_parameterized(&binding.field.ty, where_clause.params, None) { where_clause.inner.predicates.push(cg::where_predicate( binding.field.ty.clone(), &["std", "clone", "Clone"], + None, )); } quote! { let #mapped_binding = ::std::clone::Clone::clone(#binding); } } else { - where_clause.add_trait_bound(binding.field.ty.clone()); + where_clause.add_trait_bound(&binding.field.ty); quote! { let #mapped_binding = ::values::animated::ToAnimatedZero::to_animated_zero(#binding)?; diff --git a/components/style_derive/to_computed_value.rs b/components/style_derive/to_computed_value.rs index ca84265ceeb..74655743eea 100644 --- a/components/style_derive/to_computed_value.rs +++ b/components/style_derive/to_computed_value.rs @@ -3,26 +3,26 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use cg; -use quote; -use syn; +use quote::Tokens; +use syn::DeriveInput; use synstructure::BindStyle; -pub fn derive(input: syn::DeriveInput) -> quote::Tokens { +pub fn derive(input: DeriveInput) -> Tokens { let name = &input.ident; let trait_path = &["values", "computed", "ToComputedValue"]; let (impl_generics, ty_generics, mut where_clause, computed_value_type) = cg::fmap_trait_parts(&input, trait_path, "ComputedValue"); - for param in &input.generics.ty_params { - where_clause.add_trait_bound( - syn::Ty::Path(None, param.ident.clone().into()), - ); - } let to_body = cg::fmap_match(&input, BindStyle::Ref, |binding| { - quote!(::values::computed::ToComputedValue::to_computed_value(#binding, context)) + where_clause.add_trait_bound(&binding.field.ty); + quote! { + ::values::computed::ToComputedValue::to_computed_value(#binding, context) + } }); let from_body = cg::fmap_match(&input, BindStyle::Ref, |binding| { - quote!(::values::computed::ToComputedValue::from_computed_value(#binding)) + quote! { + ::values::computed::ToComputedValue::from_computed_value(#binding) + } }); quote! { diff --git a/components/style_derive/to_css.rs b/components/style_derive/to_css.rs index 6dd7567a5fb..bd66b9b8caa 100644 --- a/components/style_derive/to_css.rs +++ b/components/style_derive/to_css.rs @@ -21,7 +21,7 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { let mut expr = if !bindings.is_empty() { let mut expr = quote! {}; for binding in bindings { - where_clause.add_trait_bound(binding.field.ty.clone()); + where_clause.add_trait_bound(&binding.field.ty); expr = quote! { #expr writer.item(#binding)?; From 735e093de7d52179e85b3093b8634c18d06dc17b Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 26 Aug 2017 12:56:50 +0200 Subject: [PATCH 10/18] Implement #[compute(clone)] for #[derive(ToComputedValue)] --- components/style/values/computed/image.rs | 25 +------------ components/style/values/generics/grid.rs | 31 +++------------- components/style/values/generics/image.rs | 4 ++- components/style/values/specified/grid.rs | 37 -------------------- components/style_derive/lib.rs | 2 +- components/style_derive/to_computed_value.rs | 33 ++++++++++++++--- 6 files changed, 37 insertions(+), 95 deletions(-) diff --git a/components/style/values/computed/image.rs b/components/style/values/computed/image.rs index f188adf3f7d..952e213ccb9 100644 --- a/components/style/values/computed/image.rs +++ b/components/style/values/computed/image.rs @@ -18,8 +18,7 @@ use values::generics::image::{CompatMode, ColorStop as GenericColorStop, EndingS use values::generics::image::{Gradient as GenericGradient, GradientItem as GenericGradientItem}; use values::generics::image::{Image as GenericImage, GradientKind as GenericGradientKind}; use values::generics::image::{LineDirection as GenericLineDirection, MozImageRect as GenericMozImageRect}; -use values::specified::image::{Gradient as SpecifiedGradient, LineDirection as SpecifiedLineDirection}; -use values::specified::image::{GradientKind as SpecifiedGradientKind}; +use values::specified::image::LineDirection as SpecifiedLineDirection; use values::specified::position::{X, Y}; /// A computed image layer. @@ -181,25 +180,3 @@ impl ToComputedValue for SpecifiedLineDirection { } } } - -impl ToComputedValue for SpecifiedGradient { - type ComputedValue = Gradient; - - fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { - Self::ComputedValue { - kind: self.kind.to_computed_value(context), - items: self.items.to_computed_value(context), - repeating: self.repeating, - compat_mode: self.compat_mode - } - } - - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - Self { - kind: SpecifiedGradientKind::from_computed_value(&computed.kind), - items: ToComputedValue::from_computed_value(&computed.items), - repeating: computed.repeating, - compat_mode: computed.compat_mode - } - } -} diff --git a/components/style/values/generics/grid.rs b/components/style/values/generics/grid.rs index fba3d747fa8..93d00b8325f 100644 --- a/components/style/values/generics/grid.rs +++ b/components/style/values/generics/grid.rs @@ -349,8 +349,8 @@ no_viewport_percentage!(RepeatCount); /// /// It can also hold `repeat()` function parameters, which expands into the respective /// values in its computed form. -#[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[derive(Clone, Debug, PartialEq, ToComputedValue)] pub struct TrackRepeat { /// The number of times for the value to be repeated (could also be `auto-fit` or `auto-fill`) pub count: RepeatCount, @@ -359,6 +359,7 @@ pub struct TrackRepeat { /// If there's no ``, then it's represented by an empty vector. /// For N `` values, there will be N+1 ``, and so this vector's /// length is always one value more than that of the ``. + #[compute(clone)] pub line_names: Box<[Box<[CustomIdent]>]>, /// `` values. pub track_sizes: Vec>, @@ -446,31 +447,6 @@ impl TrackRepeat { } } } -impl ToComputedValue for TrackRepeat { - type ComputedValue = TrackRepeat; - - #[inline] - fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { - TrackRepeat { - count: self.count, - track_sizes: self.track_sizes.iter() - .map(|val| val.to_computed_value(context)) - .collect(), - line_names: self.line_names.clone(), - } - } - - #[inline] - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - TrackRepeat { - count: computed.count, - track_sizes: computed.track_sizes.iter() - .map(ToComputedValue::from_computed_value) - .collect(), - line_names: computed.line_names.clone(), - } - } -} /// The type of a `` as determined during parsing. /// @@ -500,8 +476,8 @@ impl ComputedValueAsSpecified for TrackListType {} /// A grid `` type. /// /// https://drafts.csswg.org/css-grid/#typedef-track-list -#[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[derive(Clone, Debug, PartialEq, ToComputedValue)] pub struct TrackList { /// The type of this `` (auto, explicit or general). /// @@ -515,6 +491,7 @@ pub struct TrackList { /// If there's no ``, then it's represented by an empty vector. /// For N values, there will be N+1 ``, and so this vector's /// length is always one value more than that of the ``. + #[compute(clone)] pub line_names: Box<[Box<[CustomIdent]>]>, /// `` value. There can only be one `` in a TrackList. pub auto_repeat: Option>, diff --git a/components/style/values/generics/image.rs b/components/style/values/generics/image.rs index bc8f038ffb2..3e977759d70 100644 --- a/components/style/values/generics/image.rs +++ b/components/style/values/generics/image.rs @@ -35,16 +35,18 @@ pub enum Image { /// A CSS gradient. /// https://drafts.csswg.org/css-images/#gradients -#[derive(Clone, Debug, HasViewportPercentage, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToComputedValue)] pub struct Gradient { /// Gradients can be linear or radial. pub kind: GradientKind, /// The color stops and interpolation hints. pub items: Vec>, /// True if this is a repeating gradient. + #[compute(clone)] pub repeating: bool, /// Compatibility mode. + #[compute(clone)] pub compat_mode: CompatMode, } diff --git a/components/style/values/specified/grid.rs b/components/style/values/specified/grid.rs index 6499bbcb49b..72ce404d25c 100644 --- a/components/style/values/specified/grid.rs +++ b/components/style/values/specified/grid.rs @@ -11,7 +11,6 @@ use std::ascii::AsciiExt; use std::mem; use style_traits::{HasViewportPercentage, ParseError, StyleParseError}; use values::{CSSFloat, CustomIdent}; -use values::computed::{self, Context, ToComputedValue}; use values::generics::grid::{GridTemplateComponent, RepeatCount, TrackBreadth, TrackKeyword, TrackRepeat}; use values::generics::grid::{LineNameList, TrackSize, TrackList, TrackListType}; use values::specified::LengthOrPercentage; @@ -286,42 +285,6 @@ impl HasViewportPercentage for TrackList { } } - -impl ToComputedValue for TrackList { - type ComputedValue = TrackList; - - #[inline] - fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { - let mut values = Vec::with_capacity(self.values.len() + 1); - for value in self.values.iter().map(|val| val.to_computed_value(context)) { - values.push(value); - } - - TrackList { - list_type: self.list_type.to_computed_value(context), - values: values, - line_names: self.line_names.clone(), - auto_repeat: self.auto_repeat.clone().map(|repeat| repeat.to_computed_value(context)), - } - } - - #[inline] - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - let mut values = Vec::with_capacity(computed.values.len() + 1); - for value in computed.values.iter().map(ToComputedValue::from_computed_value) { - values.push(value); - } - - TrackList { - list_type: computed.list_type, - values: values, - line_names: computed.line_names.clone(), - auto_repeat: computed.auto_repeat.clone().map(|ref repeat| TrackRepeat::from_computed_value(repeat)), - } - } -} - - impl Parse for GridTemplateComponent { // FIXME: Derive Parse (probably with None_) fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result> { diff --git a/components/style_derive/lib.rs b/components/style_derive/lib.rs index 342d9cc4b9b..4e2ff9e3fca 100644 --- a/components/style_derive/lib.rs +++ b/components/style_derive/lib.rs @@ -49,7 +49,7 @@ pub fn derive_to_animated_zero(stream: TokenStream) -> TokenStream { to_animated_zero::derive(input).to_string().parse().unwrap() } -#[proc_macro_derive(ToComputedValue)] +#[proc_macro_derive(ToComputedValue, attributes(compute))] pub fn derive_to_computed_value(stream: TokenStream) -> TokenStream { let input = syn::parse_derive_input(&stream.to_string()).unwrap(); to_computed_value::derive(input).to_string().parse().unwrap() diff --git a/components/style_derive/to_computed_value.rs b/components/style_derive/to_computed_value.rs index 74655743eea..7e4db276edd 100644 --- a/components/style_derive/to_computed_value.rs +++ b/components/style_derive/to_computed_value.rs @@ -14,14 +14,31 @@ pub fn derive(input: DeriveInput) -> Tokens { cg::fmap_trait_parts(&input, trait_path, "ComputedValue"); let to_body = cg::fmap_match(&input, BindStyle::Ref, |binding| { - where_clause.add_trait_bound(&binding.field.ty); - quote! { - ::values::computed::ToComputedValue::to_computed_value(#binding, context) + let attrs = cg::parse_field_attrs::(&binding.field); + if attrs.clone { + if cg::is_parameterized(&binding.field.ty, where_clause.params, None) { + where_clause.inner.predicates.push(cg::where_predicate( + binding.field.ty.clone(), + &["std", "clone", "Clone"], + None, + )); + } + quote! { ::std::clone::Clone::clone(#binding) } + } else { + where_clause.add_trait_bound(&binding.field.ty); + quote! { + ::values::computed::ToComputedValue::to_computed_value(#binding, context) + } } }); let from_body = cg::fmap_match(&input, BindStyle::Ref, |binding| { - quote! { - ::values::computed::ToComputedValue::from_computed_value(#binding) + let attrs = cg::parse_field_attrs::(&binding.field); + if attrs.clone { + quote! { ::std::clone::Clone::clone(#binding) } + } else { + quote! { + ::values::computed::ToComputedValue::from_computed_value(#binding) + } } }); @@ -46,3 +63,9 @@ pub fn derive(input: DeriveInput) -> Tokens { } } } + +#[darling(attributes(compute), default)] +#[derive(Default, FromField)] +struct ComputedValueAttrs { + clone: bool, +} From 3751fe9fdcbe8b00e3f977b418154bf999e13c78 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Mon, 28 Aug 2017 10:38:11 +0200 Subject: [PATCH 11/18] Derive ToComputedValue for TrackBreadth --- .../style/properties/longhand/font.mako.rs | 3 -- components/style/values/computed/mod.rs | 1 + components/style/values/generics/grid.rs | 30 +++---------------- 3 files changed, 5 insertions(+), 29 deletions(-) diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs index e4d257d02a6..51c2e38181c 100644 --- a/components/style/properties/longhand/font.mako.rs +++ b/components/style/properties/longhand/font.mako.rs @@ -2265,11 +2265,8 @@ https://drafts.csswg.org/css-fonts-4/#low-level-font-variation-settings-control- predefined_type="Number" gecko_ffi_name="mScriptSizeMultiplier" spec="Internal (not web-exposed)" internal="True"> - use values::computed::ComputedValueAsSpecified; pub use self::computed_value::T as SpecifiedValue; - impl ComputedValueAsSpecified for SpecifiedValue {} - pub mod computed_value { pub type T = f32; } diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 22d958f90a6..f3d6c5d658d 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -327,6 +327,7 @@ impl ToComputedValue for T impl ComputedValueAsSpecified for Atom {} impl ComputedValueAsSpecified for bool {} +impl ComputedValueAsSpecified for f32 {} impl ComputedValueAsSpecified for specified::BorderStyle {} diff --git a/components/style/values/generics/grid.rs b/components/style/values/generics/grid.rs index 93d00b8325f..87f427f6cb3 100644 --- a/components/style/values/generics/grid.rs +++ b/components/style/values/generics/grid.rs @@ -10,7 +10,7 @@ use parser::{Parse, ParserContext}; use std::{fmt, mem, usize}; use style_traits::{ToCss, ParseError, StyleParseError}; use values::{CSSFloat, CustomIdent, serialize_dimension}; -use values::computed::{ComputedValueAsSpecified, Context, ToComputedValue}; +use values::computed::ComputedValueAsSpecified; use values::specified::Integer; use values::specified::grid::parse_line_names; @@ -137,13 +137,14 @@ define_css_keyword_enum!{ TrackKeyword: "max-content" => MaxContent, "min-content" => MinContent } +impl ComputedValueAsSpecified for TrackKeyword {} -#[derive(Clone, Debug, PartialEq)] -#[cfg_attr(feature = "servo", derive(HeapSizeOf))] /// A track breadth for explicit grid track sizing. It's generic solely to /// avoid re-implementing it for the computed type. /// /// https://drafts.csswg.org/css-grid/#typedef-track-breadth +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[derive(Clone, Debug, PartialEq, ToComputedValue)] pub enum TrackBreadth { /// The generic type is almost always a non-negative `` Breadth(L), @@ -176,29 +177,6 @@ impl ToCss for TrackBreadth { } } -impl ToComputedValue for TrackBreadth { - type ComputedValue = TrackBreadth; - - #[inline] - fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { - match *self { - TrackBreadth::Breadth(ref lop) => TrackBreadth::Breadth(lop.to_computed_value(context)), - TrackBreadth::Flex(fr) => TrackBreadth::Flex(fr), - TrackBreadth::Keyword(k) => TrackBreadth::Keyword(k), - } - } - - #[inline] - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - match *computed { - TrackBreadth::Breadth(ref lop) => - TrackBreadth::Breadth(ToComputedValue::from_computed_value(lop)), - TrackBreadth::Flex(fr) => TrackBreadth::Flex(fr), - TrackBreadth::Keyword(k) => TrackBreadth::Keyword(k), - } - } -} - /// A `` type for explicit grid track sizing. Like ``, this is /// generic only to avoid code bloat. It only takes `` /// From 4a4bf895759aa7be08944b3998f64c0c2572a4ad Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 26 Aug 2017 16:25:28 +0200 Subject: [PATCH 12/18] Implement #[animate(fallback)] for #[derive(Animate)] This allows us to derive the Animate trait, providing a fallback function for when the 2 values aren't similar. --- .../helpers/animated_properties.mako.rs | 100 ------------------ components/style/values/computed/length.rs | 61 ++++++++++- components/style_derive/animate.rs | 35 ++++-- components/style_derive/cg.rs | 12 ++- .../style_derive/compute_squared_distance.rs | 4 +- components/style_derive/lib.rs | 2 +- components/style_derive/to_animated_zero.rs | 6 +- 7 files changed, 99 insertions(+), 121 deletions(-) diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index 458814ba17f..9a50e2dd3ca 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -812,73 +812,6 @@ impl Animate for CalcLengthOrPercentage { } } -/// https://drafts.csswg.org/css-transitions/#animtype-lpcalc -impl Animate for LengthOrPercentage { - #[inline] - fn animate(&self, other: &Self, procedure: Procedure) -> Result { - match (self, other) { - ( - &LengthOrPercentage::Length(ref this), - &LengthOrPercentage::Length(ref other), - ) => { - Ok(LengthOrPercentage::Length(this.animate(other, procedure)?)) - }, - ( - &LengthOrPercentage::Percentage(ref this), - &LengthOrPercentage::Percentage(ref other), - ) => { - Ok(LengthOrPercentage::Percentage(this.animate(other, procedure)?)) - }, - (this, other) => { - // Special handling for zero values since these should not require calc(). - if this.is_definitely_zero() { - return other.to_animated_zero()?.animate(other, procedure); - } - if other.is_definitely_zero() { - return this.animate(&this.to_animated_zero()?, procedure); - } - - let this = CalcLengthOrPercentage::from(*this); - let other = CalcLengthOrPercentage::from(*other); - Ok(LengthOrPercentage::Calc(this.animate(&other, procedure)?)) - } - } - } -} - -/// https://drafts.csswg.org/css-transitions/#animtype-lpcalc -impl Animate for LengthOrPercentageOrAuto { - #[inline] - fn animate(&self, other: &Self, procedure: Procedure) -> Result { - match (self, other) { - ( - &LengthOrPercentageOrAuto::Length(ref this), - &LengthOrPercentageOrAuto::Length(ref other), - ) => { - Ok(LengthOrPercentageOrAuto::Length(this.animate(other, procedure)?)) - }, - ( - &LengthOrPercentageOrAuto::Percentage(ref this), - &LengthOrPercentageOrAuto::Percentage(ref other), - ) => { - Ok(LengthOrPercentageOrAuto::Percentage( - this.animate(other, procedure)?, - )) - }, - (&LengthOrPercentageOrAuto::Auto, &LengthOrPercentageOrAuto::Auto) => { - Ok(LengthOrPercentageOrAuto::Auto) - }, - (this, other) => { - let this: Option = From::from(*this); - let other: Option = From::from(*other); - Ok(LengthOrPercentageOrAuto::Calc( - this.animate(&other, procedure)?.ok_or(())?, - )) - }, - } - } -} - impl ToAnimatedZero for LengthOrPercentageOrAuto { #[inline] fn to_animated_zero(&self) -> Result { @@ -893,39 +826,6 @@ impl ToAnimatedZero for LengthOrPercentageOrAuto { } } -/// https://drafts.csswg.org/css-transitions/#animtype-lpcalc -impl Animate for LengthOrPercentageOrNone { - #[inline] - fn animate(&self, other: &Self, procedure: Procedure) -> Result { - match (self, other) { - ( - &LengthOrPercentageOrNone::Length(ref this), - &LengthOrPercentageOrNone::Length(ref other), - ) => { - Ok(LengthOrPercentageOrNone::Length(this.animate(other, procedure)?)) - }, - ( - &LengthOrPercentageOrNone::Percentage(ref this), - &LengthOrPercentageOrNone::Percentage(ref other), - ) => { - Ok(LengthOrPercentageOrNone::Percentage( - this.animate(other, procedure)?, - )) - } - (&LengthOrPercentageOrNone::None, &LengthOrPercentageOrNone::None) => { - Ok(LengthOrPercentageOrNone::None) - }, - (this, other) => { - let this = >::from(*this); - let other = >::from(*other); - Ok(LengthOrPercentageOrNone::Calc( - this.animate(&other, procedure)?.ok_or(())?, - )) - }, - } - } -} - impl ToAnimatedZero for LengthOrPercentageOrNone { #[inline] fn to_animated_zero(&self) -> Result { diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs index a6600a806a2..94fd0bc12a0 100644 --- a/components/style/values/computed/length.rs +++ b/components/style/values/computed/length.rs @@ -11,6 +11,7 @@ use style_traits::ToCss; use style_traits::values::specified::AllowedLengthType; use super::{Number, ToComputedValue, Context, Percentage}; use values::{Auto, CSSFloat, Either, ExtremumLength, None_, Normal, specified}; +use values::animated::{Animate, Procedure, ToAnimatedZero}; use values::computed::{NonNegativeAu, NonNegativeNumber}; use values::distance::{ComputeSquaredDistance, SquaredDistance}; use values::generics::NonNegative; @@ -274,14 +275,36 @@ impl ToComputedValue for specified::CalcLengthOrPercentage { } #[allow(missing_docs)] +#[animate(fallback = "Self::animate_fallback")] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] -#[derive(Clone, Copy, PartialEq, ToAnimatedZero, ToCss)] +#[derive(Animate, Clone, Copy, PartialEq, ToAnimatedZero, ToCss)] pub enum LengthOrPercentage { Length(Au), Percentage(Percentage), Calc(CalcLengthOrPercentage), } +impl LengthOrPercentage { + /// https://drafts.csswg.org/css-transitions/#animtype-lpcalc + fn animate_fallback( + &self, + other: &Self, + procedure: Procedure, + ) -> Result { + // Special handling for zero values since these should not require calc(). + if self.is_definitely_zero() { + return other.to_animated_zero()?.animate(other, procedure); + } + if other.is_definitely_zero() { + return self.animate(&self.to_animated_zero()?, procedure); + } + + let this = CalcLengthOrPercentage::from(*self); + let other = CalcLengthOrPercentage::from(*other); + Ok(LengthOrPercentage::Calc(this.animate(&other, procedure)?)) + } +} + impl ComputeSquaredDistance for LengthOrPercentage { #[inline] fn compute_squared_distance(&self, other: &Self) -> Result { @@ -415,8 +438,9 @@ impl ToComputedValue for specified::LengthOrPercentage { } #[allow(missing_docs)] +#[animate(fallback = "Self::animate_fallback")] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] -#[derive(Clone, Copy, PartialEq, ToCss)] +#[derive(Animate, Clone, Copy, PartialEq, ToCss)] pub enum LengthOrPercentageOrAuto { Length(Au), Percentage(Percentage), @@ -424,6 +448,21 @@ pub enum LengthOrPercentageOrAuto { Calc(CalcLengthOrPercentage), } +impl LengthOrPercentageOrAuto { + /// https://drafts.csswg.org/css-transitions/#animtype-lpcalc + fn animate_fallback( + &self, + other: &Self, + procedure: Procedure, + ) -> Result { + let this = >::from(*self); + let other = >::from(*other); + Ok(LengthOrPercentageOrAuto::Calc( + this.animate(&other, procedure)?.ok_or(())?, + )) + } +} + impl ComputeSquaredDistance for LengthOrPercentageOrAuto { #[inline] fn compute_squared_distance(&self, other: &Self) -> Result { @@ -510,8 +549,9 @@ impl ToComputedValue for specified::LengthOrPercentageOrAuto { } #[allow(missing_docs)] +#[animate(fallback = "Self::animate_fallback")] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] -#[derive(Clone, Copy, PartialEq, ToCss)] +#[derive(Animate, Clone, Copy, PartialEq, ToCss)] pub enum LengthOrPercentageOrNone { Length(Au), Percentage(Percentage), @@ -519,6 +559,21 @@ pub enum LengthOrPercentageOrNone { None, } +impl LengthOrPercentageOrNone { + /// https://drafts.csswg.org/css-transitions/#animtype-lpcalc + fn animate_fallback( + &self, + other: &Self, + procedure: Procedure, + ) -> Result { + let this = >::from(*self); + let other = >::from(*other); + Ok(LengthOrPercentageOrNone::Calc( + this.animate(&other, procedure)?.ok_or(())?, + )) + } +} + impl ComputeSquaredDistance for LengthOrPercentageOrNone { #[inline] fn compute_squared_distance(&self, other: &Self) -> Result { diff --git a/components/style_derive/animate.rs b/components/style_derive/animate.rs index 9153b7792e7..d4fe5c94a53 100644 --- a/components/style_derive/animate.rs +++ b/components/style_derive/animate.rs @@ -3,21 +3,22 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use cg; -use quote; -use syn; +use quote::Tokens; +use syn::{DeriveInput, Path}; -pub fn derive(input: syn::DeriveInput) -> quote::Tokens { +pub fn derive(input: DeriveInput) -> Tokens { let name = &input.ident; let trait_path = &["values", "animated", "Animate"]; let (impl_generics, ty_generics, mut where_clause) = cg::trait_parts(&input, trait_path); + let input_attrs = cg::parse_input_attrs::(&input); let variants = cg::variants(&input); let mut match_body = quote!(); let mut append_error_clause = variants.len() > 1; match_body.append_all(variants.iter().flat_map(|variant| { - let attrs = cg::parse_variant_attrs::(variant); - if attrs.error { + let variant_attrs = cg::parse_variant_attrs::(variant); + if variant_attrs.error { append_error_clause = true; return None; } @@ -28,7 +29,7 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { let mut computations = quote!(); let iter = result_info.iter().zip(this_info.iter().zip(&other_info)); computations.append_all(iter.map(|(result, (this, other))| { - let field_attrs = cg::parse_field_attrs::(&result.field); + let field_attrs = cg::parse_field_attrs::(&result.field); if field_attrs.constant { if cg::is_parameterized(&result.field.ty, where_clause.params, None) { where_clause.inner.predicates.push(cg::where_predicate( @@ -65,7 +66,13 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { })); if append_error_clause { - match_body = quote! { #match_body, _ => Err(()), }; + if let Some(fallback) = input_attrs.fallback { + match_body.append(quote! { + (this, other) => #fallback(this, other, procedure) + }); + } else { + match_body.append(quote! { _ => Err(()) }); + } } quote! { @@ -85,14 +92,20 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { } } -#[derive(Default, FromVariant)] +#[darling(attributes(animate), default)] +#[derive(Default, FromDeriveInput)] +struct AnimateInputAttrs { + fallback: Option, +} + #[darling(attributes(animation), default)] -pub struct AnimateAttrs { +#[derive(Default, FromVariant)] +pub struct AnimationVariantAttrs { pub error: bool, } -#[derive(Default, FromField)] #[darling(attributes(animation), default)] -pub struct AnimateFieldAttrs { +#[derive(Default, FromField)] +pub struct AnimationFieldAttrs { pub constant: bool, } diff --git a/components/style_derive/cg.rs b/components/style_derive/cg.rs index 89748939c11..6937d5836d2 100644 --- a/components/style_derive/cg.rs +++ b/components/style_derive/cg.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use darling::{FromField, FromVariant}; +use darling::{FromDeriveInput, FromField, FromVariant}; use quote::{ToTokens, Tokens}; use std::borrow::Cow; use std::collections::HashSet; @@ -276,6 +276,16 @@ where } } +pub fn parse_input_attrs(input: &DeriveInput) -> A +where + A: FromDeriveInput, +{ + match A::from_derive_input(input) { + Ok(attrs) => attrs, + Err(e) => panic!("failed to parse input attributes: {}", e), + } +} + pub fn parse_variant_attrs(variant: &Variant) -> A where A: FromVariant, diff --git a/components/style_derive/compute_squared_distance.rs b/components/style_derive/compute_squared_distance.rs index 9d92c18fcce..0cc19d2d737 100644 --- a/components/style_derive/compute_squared_distance.rs +++ b/components/style_derive/compute_squared_distance.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use animate::AnimateAttrs; +use animate::AnimationVariantAttrs; use cg; use quote; use syn; @@ -17,7 +17,7 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { let mut match_body = quote!(); let mut append_error_clause = variants.len() > 1; match_body.append_all(variants.iter().map(|variant| { - let attrs = cg::parse_variant_attrs::(variant); + let attrs = cg::parse_variant_attrs::(variant); if attrs.error { append_error_clause = true; return None; diff --git a/components/style_derive/lib.rs b/components/style_derive/lib.rs index 4e2ff9e3fca..a0e09477c57 100644 --- a/components/style_derive/lib.rs +++ b/components/style_derive/lib.rs @@ -19,7 +19,7 @@ mod to_animated_zero; mod to_computed_value; mod to_css; -#[proc_macro_derive(Animate, attributes(animation))] +#[proc_macro_derive(Animate, attributes(animate, animation))] pub fn derive_animate(stream: TokenStream) -> TokenStream { let input = syn::parse_derive_input(&stream.to_string()).unwrap(); animate::derive(input).to_string().parse().unwrap() diff --git a/components/style_derive/to_animated_zero.rs b/components/style_derive/to_animated_zero.rs index f733bfa4ed5..be1210faa7a 100644 --- a/components/style_derive/to_animated_zero.rs +++ b/components/style_derive/to_animated_zero.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use animate::{AnimateAttrs, AnimateFieldAttrs}; +use animate::{AnimationVariantAttrs, AnimationFieldAttrs}; use cg; use quote; use syn; @@ -16,7 +16,7 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { let bind_opts = BindStyle::Ref.into(); let to_body = synstructure::each_variant(&input, &bind_opts, |bindings, variant| { - let attrs = cg::parse_variant_attrs::(variant); + let attrs = cg::parse_variant_attrs::(variant); if attrs.error { return Some(quote! { Err(()) }); } @@ -25,7 +25,7 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { let bindings_pairs = bindings.into_iter().zip(mapped_bindings); let mut computations = quote!(); computations.append_all(bindings_pairs.map(|(binding, mapped_binding)| { - let field_attrs = cg::parse_field_attrs::(&binding.field); + let field_attrs = cg::parse_field_attrs::(&binding.field); if field_attrs.constant { if cg::is_parameterized(&binding.field.ty, where_clause.params, None) { where_clause.inner.predicates.push(cg::where_predicate( From 318d8696e5c360d648bd9a4d87e9cd1055f63ed4 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 26 Aug 2017 16:29:09 +0200 Subject: [PATCH 13/18] Derive Animate and ComputeSquaredDistance for computed font-size-adjust --- .../style/properties/longhand/font.mako.rs | 27 +++---------------- 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs index 51c2e38181c..7dc51dca3d4 100644 --- a/components/style/properties/longhand/font.mako.rs +++ b/components/style/properties/longhand/font.mako.rs @@ -1116,12 +1116,12 @@ ${helpers.single_keyword_system("font-variant-caps", pub mod computed_value { use values::CSSFloat; - use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero}; - use values::distance::{ComputeSquaredDistance, SquaredDistance}; + use values::animated::{ToAnimatedValue, ToAnimatedZero}; #[cfg_attr(feature = "servo", derive(HeapSizeOf))] - #[derive(Clone, Copy, Debug, PartialEq, ToCss)] + #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, PartialEq, ToCss)] pub enum T { + #[animation(error)] None, Number(CSSFloat), } @@ -1136,27 +1136,6 @@ ${helpers.single_keyword_system("font-variant-caps", } } - impl Animate for T { - fn animate(&self, other: &Self, procedure: Procedure) -> Result { - match (self, other) { - (&T::Number(ref number), &T::Number(ref other)) => { - Ok(T::Number(number.animate(other, procedure)?)) - }, - _ => Err(()), - } - } - } - - impl ComputeSquaredDistance for T { - #[inline] - fn compute_squared_distance(&self, other: &Self) -> Result { - match (self, other) { - (&T::Number(ref this), &T::Number(ref other)) => this.compute_squared_distance(other), - _ => Err(()), - } - } - } - impl ToAnimatedZero for T { #[inline] fn to_animated_zero(&self) -> Result { Err(()) } From b543b17cf00b241790d72a542e50fa19244fc0d6 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 26 Aug 2017 16:39:59 +0200 Subject: [PATCH 14/18] Derive Animate for BackgroundSize --- .../style/values/computed/background.rs | 19 +------------------ .../style/values/generics/background.rs | 5 ++++- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/components/style/values/computed/background.rs b/components/style/values/computed/background.rs index 82b6ba74f28..f3180c54ebe 100644 --- a/components/style/values/computed/background.rs +++ b/components/style/values/computed/background.rs @@ -6,7 +6,7 @@ use properties::animated_properties::RepeatableListAnimatable; use properties::longhands::background_size::computed_value::T as BackgroundSizeList; -use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero}; +use values::animated::{ToAnimatedValue, ToAnimatedZero}; use values::computed::length::LengthOrPercentageOrAuto; use values::generics::background::BackgroundSize as GenericBackgroundSize; @@ -15,23 +15,6 @@ pub type BackgroundSize = GenericBackgroundSize; impl RepeatableListAnimatable for BackgroundSize {} -impl Animate for BackgroundSize { - fn animate(&self, other: &Self, procedure: Procedure) -> Result { - match (self, other) { - ( - &GenericBackgroundSize::Explicit { width: self_width, height: self_height }, - &GenericBackgroundSize::Explicit { width: other_width, height: other_height }, - ) => { - Ok(GenericBackgroundSize::Explicit { - width: self_width.animate(&other_width, procedure)?, - height: self_height.animate(&other_height, procedure)?, - }) - } - _ => Err(()), - } - } -} - impl ToAnimatedZero for BackgroundSize { #[inline] fn to_animated_zero(&self) -> Result { Err(()) } diff --git a/components/style/values/generics/background.rs b/components/style/values/generics/background.rs index 8a79691f3b9..abcfb655eec 100644 --- a/components/style/values/generics/background.rs +++ b/components/style/values/generics/background.rs @@ -5,8 +5,9 @@ //! Generic types for CSS values related to backgrounds. /// A generic value for the `background-size` property. -#[derive(Clone, ComputeSquaredDistance, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue, ToCss)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug)] +#[derive(HasViewportPercentage, PartialEq, ToComputedValue, ToCss)] pub enum BackgroundSize { /// ` ` Explicit { @@ -16,8 +17,10 @@ pub enum BackgroundSize { height: LengthOrPercentageOrAuto }, /// `cover` + #[animation(error)] Cover, /// `contain` + #[animation(error)] Contain, } From 1ace6d4c7f07d95dbdd233581745826cdf05b101 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 26 Aug 2017 16:43:44 +0200 Subject: [PATCH 15/18] Derive Animate for computed::Angle --- components/style/values/computed/angle.rs | 25 ++++++----------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/components/style/values/computed/angle.rs b/components/style/values/computed/angle.rs index d5461d1cbf9..467a9501196 100644 --- a/components/style/values/computed/angle.rs +++ b/components/style/values/computed/angle.rs @@ -12,8 +12,10 @@ use values::animated::{Animate, Procedure}; use values::distance::{ComputeSquaredDistance, SquaredDistance}; /// A computed angle. +#[animate(fallback = "Self::animate_fallback")] #[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))] -#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, PartialOrd, ToAnimatedZero)] +#[derive(Animate, Clone, Copy, Debug, HasViewportPercentage, PartialEq)] +#[derive(PartialOrd, ToAnimatedZero)] pub enum Angle { /// An angle with degree unit. Degree(CSSFloat), @@ -62,26 +64,11 @@ impl Angle { pub fn zero() -> Self { Angle::Radian(0.0) } -} -/// https://drafts.csswg.org/css-transitions/#animtype-number -impl Animate for Angle { + /// https://drafts.csswg.org/css-transitions/#animtype-number #[inline] - fn animate(&self, other: &Self, procedure: Procedure) -> Result { - match (self, other) { - (&Angle::Degree(ref this), &Angle::Degree(ref other)) => { - Ok(Angle::Degree(this.animate(other, procedure)?)) - }, - (&Angle::Gradian(ref this), &Angle::Gradian(ref other)) => { - Ok(Angle::Gradian(this.animate(other, procedure)?)) - }, - (&Angle::Turn(ref this), &Angle::Turn(ref other)) => { - Ok(Angle::Turn(this.animate(other, procedure)?)) - }, - _ => { - Ok(Angle::from_radians(self.radians().animate(&other.radians(), procedure)?)) - }, - } + fn animate_fallback(&self, other: &Self, procedure: Procedure) -> Result { + Ok(Angle::from_radians(self.radians().animate(&other.radians(), procedure)?)) } } From 4faadb489fb4f92d3e54c37121c69182f7e2a841 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 26 Aug 2017 16:55:42 +0200 Subject: [PATCH 16/18] Implement #[css(derive_debug)] This makes #[derive(ToCss)] derive Debug with a simple call to the to_css method. --- components/style/values/computed/length.rs | 35 ++----------------- components/style_derive/to_css.rs | 39 +++++++++++++++++----- 2 files changed, 33 insertions(+), 41 deletions(-) diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs index 94fd0bc12a0..535219d187d 100644 --- a/components/style/values/computed/length.rs +++ b/components/style/values/computed/length.rs @@ -277,6 +277,7 @@ impl ToComputedValue for specified::CalcLengthOrPercentage { #[allow(missing_docs)] #[animate(fallback = "Self::animate_fallback")] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[css(derive_debug)] #[derive(Animate, Clone, Copy, PartialEq, ToAnimatedZero, ToCss)] pub enum LengthOrPercentage { Length(Au), @@ -391,16 +392,6 @@ impl LengthOrPercentage { } } -impl fmt::Debug for LengthOrPercentage { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - LengthOrPercentage::Length(length) => write!(f, "{:?}", length), - LengthOrPercentage::Percentage(percentage) => write!(f, "{}%", percentage.0 * 100.), - LengthOrPercentage::Calc(calc) => write!(f, "{:?}", calc), - } - } -} - impl ToComputedValue for specified::LengthOrPercentage { type ComputedValue = LengthOrPercentage; @@ -440,6 +431,7 @@ impl ToComputedValue for specified::LengthOrPercentage { #[allow(missing_docs)] #[animate(fallback = "Self::animate_fallback")] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[css(derive_debug)] #[derive(Animate, Clone, Copy, PartialEq, ToCss)] pub enum LengthOrPercentageOrAuto { Length(Au), @@ -495,17 +487,6 @@ impl LengthOrPercentageOrAuto { } } -impl fmt::Debug for LengthOrPercentageOrAuto { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - LengthOrPercentageOrAuto::Length(length) => write!(f, "{:?}", length), - LengthOrPercentageOrAuto::Percentage(percentage) => write!(f, "{}%", percentage.0 * 100.), - LengthOrPercentageOrAuto::Auto => write!(f, "auto"), - LengthOrPercentageOrAuto::Calc(calc) => write!(f, "{:?}", calc), - } - } -} - impl ToComputedValue for specified::LengthOrPercentageOrAuto { type ComputedValue = LengthOrPercentageOrAuto; @@ -551,6 +532,7 @@ impl ToComputedValue for specified::LengthOrPercentageOrAuto { #[allow(missing_docs)] #[animate(fallback = "Self::animate_fallback")] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[css(derive_debug)] #[derive(Animate, Clone, Copy, PartialEq, ToCss)] pub enum LengthOrPercentageOrNone { Length(Au), @@ -603,17 +585,6 @@ impl LengthOrPercentageOrNone { } } -impl fmt::Debug for LengthOrPercentageOrNone { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - LengthOrPercentageOrNone::Length(length) => write!(f, "{:?}", length), - LengthOrPercentageOrNone::Percentage(percentage) => write!(f, "{}%", percentage.0 * 100.), - LengthOrPercentageOrNone::Calc(calc) => write!(f, "{:?}", calc), - LengthOrPercentageOrNone::None => write!(f, "none"), - } - } -} - impl ToComputedValue for specified::LengthOrPercentageOrNone { type ComputedValue = LengthOrPercentageOrNone; diff --git a/components/style_derive/to_css.rs b/components/style_derive/to_css.rs index bd66b9b8caa..6ae438ccbd2 100644 --- a/components/style_derive/to_css.rs +++ b/components/style_derive/to_css.rs @@ -3,21 +3,22 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use cg; -use quote; -use syn; +use quote::Tokens; +use syn::DeriveInput; use synstructure; -pub fn derive(input: syn::DeriveInput) -> quote::Tokens { +pub fn derive(input: DeriveInput) -> Tokens { let name = &input.ident; let trait_path = &["style_traits", "ToCss"]; let (impl_generics, ty_generics, mut where_clause) = cg::trait_parts(&input, trait_path); + let input_attrs = cg::parse_input_attrs::(&input); let style = synstructure::BindStyle::Ref.into(); let match_body = synstructure::each_variant(&input, &style, |bindings, variant| { let mut identifier = to_css_identifier(variant.ident.as_ref()); - let css_attrs = cg::parse_variant_attrs::(variant); - let separator = if css_attrs.comma { ", " } else { " " }; + let variant_attrs = cg::parse_variant_attrs::(variant); + let separator = if variant_attrs.comma { ", " } else { " " }; let mut expr = if !bindings.is_empty() { let mut expr = quote! {}; for binding in bindings { @@ -37,7 +38,7 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { ::std::fmt::Write::write_str(dest, #identifier) } }; - if css_attrs.function { + if variant_attrs.function { identifier.push_str("("); expr = quote! { ::std::fmt::Write::write_str(dest, #identifier)?; @@ -48,7 +49,7 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { Some(expr) }); - quote! { + let mut impls = quote! { impl #impl_generics ::style_traits::ToCss for #name #ty_generics #where_clause { #[allow(unused_variables)] #[inline] @@ -61,12 +62,32 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { } } } + }; + + if input_attrs.derive_debug { + impls.append(quote! { + impl #impl_generics ::std::fmt::Debug for #name #ty_generics #where_clause { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + ::style_traits::ToCss::to_css(self, f) + } + } + }); } + + impls } -#[derive(Default, FromVariant)] #[darling(attributes(css), default)] -struct CssAttrs { +#[derive(Default, FromDeriveInput)] +struct CssInputAttrs { + derive_debug: bool, + function: bool, + comma: bool, +} + +#[darling(attributes(css), default)] +#[derive(Default, FromVariant)] +struct CssVariantAttrs { function: bool, comma: bool, } From 41c3be54ea414638e1b922d9ba06d0c98aec7988 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sat, 26 Aug 2017 18:13:40 +0200 Subject: [PATCH 17/18] Implement #[distance(fallback)] for #[derive(ComputeSquaredDistance)] --- components/style/values/computed/length.rs | 77 ++++++++----------- .../style_derive/compute_squared_distance.rs | 21 ++++- components/style_derive/lib.rs | 2 +- 3 files changed, 49 insertions(+), 51 deletions(-) diff --git a/components/style/values/computed/length.rs b/components/style/values/computed/length.rs index 535219d187d..f765b1ae5b6 100644 --- a/components/style/values/computed/length.rs +++ b/components/style/values/computed/length.rs @@ -278,7 +278,9 @@ impl ToComputedValue for specified::CalcLengthOrPercentage { #[animate(fallback = "Self::animate_fallback")] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[css(derive_debug)] -#[derive(Animate, Clone, Copy, PartialEq, ToAnimatedZero, ToCss)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, PartialEq)] +#[derive(ToAnimatedZero, ToCss)] +#[distance(fallback = "Self::compute_squared_distance_fallback")] pub enum LengthOrPercentage { Length(Au), Percentage(Percentage), @@ -304,22 +306,16 @@ impl LengthOrPercentage { let other = CalcLengthOrPercentage::from(*other); Ok(LengthOrPercentage::Calc(this.animate(&other, procedure)?)) } -} -impl ComputeSquaredDistance for LengthOrPercentage { #[inline] - fn compute_squared_distance(&self, other: &Self) -> Result { - match (self, other) { - (&LengthOrPercentage::Length(ref this), &LengthOrPercentage::Length(ref other)) => { - this.compute_squared_distance(other) - }, - (&LengthOrPercentage::Percentage(ref this), &LengthOrPercentage::Percentage(ref other)) => { - this.compute_squared_distance(other) - }, - (this, other) => { - CalcLengthOrPercentage::compute_squared_distance(&(*this).into(), &(*other).into()) - } - } + fn compute_squared_distance_fallback( + &self, + other: &Self, + ) -> Result { + CalcLengthOrPercentage::compute_squared_distance( + &(*self).into(), + &(*other).into(), + ) } } @@ -432,7 +428,8 @@ impl ToComputedValue for specified::LengthOrPercentage { #[animate(fallback = "Self::animate_fallback")] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[css(derive_debug)] -#[derive(Animate, Clone, Copy, PartialEq, ToCss)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, PartialEq, ToCss)] +#[distance(fallback = "Self::compute_squared_distance_fallback")] pub enum LengthOrPercentageOrAuto { Length(Au), Percentage(Percentage), @@ -453,22 +450,16 @@ impl LengthOrPercentageOrAuto { this.animate(&other, procedure)?.ok_or(())?, )) } -} -impl ComputeSquaredDistance for LengthOrPercentageOrAuto { #[inline] - fn compute_squared_distance(&self, other: &Self) -> Result { - match (self, other) { - (&LengthOrPercentageOrAuto::Length(ref this), &LengthOrPercentageOrAuto::Length(ref other)) => { - this.compute_squared_distance(other) - }, - (&LengthOrPercentageOrAuto::Percentage(ref this), &LengthOrPercentageOrAuto::Percentage(ref other)) => { - this.compute_squared_distance(other) - }, - (this, other) => { - >::compute_squared_distance(&(*this).into(), &(*other).into()) - } - } + fn compute_squared_distance_fallback( + &self, + other: &Self, + ) -> Result { + >::compute_squared_distance( + &(*self).into(), + &(*other).into(), + ) } } @@ -533,7 +524,8 @@ impl ToComputedValue for specified::LengthOrPercentageOrAuto { #[animate(fallback = "Self::animate_fallback")] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[css(derive_debug)] -#[derive(Animate, Clone, Copy, PartialEq, ToCss)] +#[derive(Animate, Clone, ComputeSquaredDistance, Copy, PartialEq, ToCss)] +#[distance(fallback = "Self::compute_squared_distance_fallback")] pub enum LengthOrPercentageOrNone { Length(Au), Percentage(Percentage), @@ -554,22 +546,15 @@ impl LengthOrPercentageOrNone { this.animate(&other, procedure)?.ok_or(())?, )) } -} -impl ComputeSquaredDistance for LengthOrPercentageOrNone { - #[inline] - fn compute_squared_distance(&self, other: &Self) -> Result { - match (self, other) { - (&LengthOrPercentageOrNone::Length(ref this), &LengthOrPercentageOrNone::Length(ref other)) => { - this.compute_squared_distance(other) - }, - (&LengthOrPercentageOrNone::Percentage(ref this), &LengthOrPercentageOrNone::Percentage(ref other)) => { - this.compute_squared_distance(other) - }, - (this, other) => { - >::compute_squared_distance(&(*this).into(), &(*other).into()) - } - } + fn compute_squared_distance_fallback( + &self, + other: &Self, + ) -> Result { + >::compute_squared_distance( + &(*self).into(), + &(*other).into(), + ) } } diff --git a/components/style_derive/compute_squared_distance.rs b/components/style_derive/compute_squared_distance.rs index 0cc19d2d737..cbdd9c62acc 100644 --- a/components/style_derive/compute_squared_distance.rs +++ b/components/style_derive/compute_squared_distance.rs @@ -4,15 +4,16 @@ use animate::AnimationVariantAttrs; use cg; -use quote; -use syn; +use quote::Tokens; +use syn::{DeriveInput, Path}; -pub fn derive(input: syn::DeriveInput) -> quote::Tokens { +pub fn derive(input: DeriveInput) -> Tokens { let name = &input.ident; let trait_path = &["values", "distance", "ComputeSquaredDistance"]; let (impl_generics, ty_generics, mut where_clause) = cg::trait_parts(&input, trait_path); + let input_attrs = cg::parse_input_attrs::(&input); let variants = cg::variants(&input); let mut match_body = quote!(); let mut append_error_clause = variants.len() > 1; @@ -45,7 +46,13 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { })); if append_error_clause { - match_body = quote! { #match_body, _ => Err(()), }; + if let Some(fallback) = input_attrs.fallback { + match_body.append(quote! { + (this, other) => #fallback(this, other) + }); + } else { + match_body.append(quote! { _ => Err(()) }); + } } quote! { @@ -63,3 +70,9 @@ pub fn derive(input: syn::DeriveInput) -> quote::Tokens { } } } + +#[darling(attributes(distance), default)] +#[derive(Default, FromDeriveInput)] +struct DistanceInputAttrs { + fallback: Option, +} diff --git a/components/style_derive/lib.rs b/components/style_derive/lib.rs index a0e09477c57..f98829e60bf 100644 --- a/components/style_derive/lib.rs +++ b/components/style_derive/lib.rs @@ -25,7 +25,7 @@ pub fn derive_animate(stream: TokenStream) -> TokenStream { animate::derive(input).to_string().parse().unwrap() } -#[proc_macro_derive(ComputeSquaredDistance, attributes(animation))] +#[proc_macro_derive(ComputeSquaredDistance, attributes(animation, distance))] pub fn derive_compute_squared_distance(stream: TokenStream) -> TokenStream { let input = syn::parse_derive_input(&stream.to_string()).unwrap(); compute_squared_distance::derive(input).to_string().parse().unwrap() From ba4136b5a8da58a6130aa3fab0654764bcdda25f Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Mon, 28 Aug 2017 09:37:25 +0200 Subject: [PATCH 18/18] Document how style traits can be derived --- components/style/values/animated/mod.rs | 23 ++++++++++++++++++++++- components/style/values/computed/mod.rs | 5 +++++ components/style/values/distance.rs | 11 +++++++++++ components/style_traits/values.rs | 8 ++++++-- 4 files changed, 44 insertions(+), 3 deletions(-) diff --git a/components/style/values/animated/mod.rs b/components/style/values/animated/mod.rs index 71f6e2bd4db..c2d42192fdd 100644 --- a/components/style/values/animated/mod.rs +++ b/components/style/values/animated/mod.rs @@ -28,7 +28,19 @@ use values::specified::url::SpecifiedUrl; pub mod color; pub mod effects; -/// Animating from one value to another. +/// Animate from one value to another. +/// +/// This trait is derivable with `#[derive(Animate)]`. The derived +/// implementation uses a `match` expression with identical patterns for both +/// `self` and `other`, calling `Animate::animate` on each fields of the values. +/// If a field is annotated with `#[animation(constant)]`, the two values should +/// be equal or an error is returned. +/// +/// If a variant is annotated with `#[animation(error)]`, the corresponding +/// `match` arm is not generated. +/// +/// If the two values are not similar, an error is returned unless a fallback +/// function has been specified through `#[animate(fallback)]`. pub trait Animate: Sized { /// Animate a value towards another one, given an animation procedure. fn animate(&self, other: &Self, procedure: Procedure) -> Result; @@ -51,6 +63,8 @@ pub enum Procedure { /// Conversion between computed values and intermediate values for animations. /// /// Notably, colors are represented as four floats during animations. +/// +/// This trait is derivable with `#[derive(ToAnimatedValue)]`. pub trait ToAnimatedValue { /// The type of the animated value. type AnimatedValue; @@ -66,6 +80,13 @@ pub trait ToAnimatedValue { pub trait AnimatedValueAsComputed {} /// Returns a value similar to `self` that represents zero. +/// +/// This trait is derivable with `#[derive(ToAnimatedValue)]`. If a field is +/// annotated with `#[animation(constant)]`, a clone of its value will be used +/// instead of calling `ToAnimatedZero::to_animated_zero` on it. +/// +/// If a variant is annotated with `#[animation(error)]`, the corresponding +/// `match` arm is not generated. pub trait ToAnimatedZero: Sized { /// Returns a value that, when added with an underlying value, will produce the underlying /// value. This is used for SMIL animation's "by-animation" where SMIL first interpolates from diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index f3d6c5d658d..3bb03d861de 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -199,6 +199,11 @@ impl<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> Iterator for ComputedVecIter< } /// A trait to represent the conversion between computed and specified values. +/// +/// This trait is derivable with `#[derive(ToComputedValue)]`. The derived +/// implementation just calls `ToComputedValue::to_computed_value` on each field +/// of the passed value, or `Clone::clone` if the field is annotated with +/// `#[compute(clone)]`. pub trait ToComputedValue { /// The computed value type we're going to be converted to. type ComputedValue; diff --git a/components/style/values/distance.rs b/components/style/values/distance.rs index d4eb91f112f..351f1eb021f 100644 --- a/components/style/values/distance.rs +++ b/components/style/values/distance.rs @@ -10,6 +10,17 @@ use std::iter::Sum; use std::ops::Add; /// A trait to compute squared distances between two animatable values. +/// +/// This trait is derivable with `#[derive(ComputeSquaredDistance)]`. The derived +/// implementation uses a `match` expression with identical patterns for both +/// `self` and `other`, calling `ComputeSquaredDistance::compute_squared_distance` +/// on each fields of the values. +/// +/// If a variant is annotated with `#[animation(error)]`, the corresponding +/// `match` arm is not generated. +/// +/// If the two values are not similar, an error is returned unless a fallback +/// function has been specified through `#[distance(fallback)]`. pub trait ComputeSquaredDistance { /// Computes the squared distance between two animatable values. fn compute_squared_distance(&self, other: &Self) -> Result; diff --git a/components/style_traits/values.rs b/components/style_traits/values.rs index 5e4c093fd73..94e59e26bbe 100644 --- a/components/style_traits/values.rs +++ b/components/style_traits/values.rs @@ -18,8 +18,12 @@ use std::fmt::{self, Write}; /// of their name; /// * unit variants whose name starts with "Moz" or "Webkit" are prepended /// with a "-"; -/// * variants with fields get serialised as the space-separated serialisations -/// of their fields. +/// * if `#[css(comma)]` is found on a variant, its fields are separated by +/// commas, otherwise, by spaces; +/// * if `#[css(function)]` is found on a variant, the variant name gets +/// serialised like unit variants and its fields are surrounded by parentheses; +/// * finally, one can put `#[css(derive_debug)]` on the whole type, to +/// implement `Debug` by a single call to `ToCss::to_css`. pub trait ToCss { /// Serialize `self` in CSS syntax, writing to `dest`. fn to_css(&self, dest: &mut W) -> fmt::Result where W: Write;