From eaf2f1ec33f1a130baf62c23fb7f3ea454881504 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Fri, 25 Aug 2017 23:51:12 +0200 Subject: [PATCH] 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()