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(