mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
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.
This commit is contained in:
parent
3751fe9fdc
commit
4a4bf89575
7 changed files with 99 additions and 121 deletions
|
@ -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<Self, ()> {
|
||||
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<Self, ()> {
|
||||
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<CalcLengthOrPercentage> = From::from(*this);
|
||||
let other: Option<CalcLengthOrPercentage> = From::from(*other);
|
||||
Ok(LengthOrPercentageOrAuto::Calc(
|
||||
this.animate(&other, procedure)?.ok_or(())?,
|
||||
))
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToAnimatedZero for LengthOrPercentageOrAuto {
|
||||
#[inline]
|
||||
fn to_animated_zero(&self) -> Result<Self, ()> {
|
||||
|
@ -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<Self, ()> {
|
||||
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 = <Option<CalcLengthOrPercentage>>::from(*this);
|
||||
let other = <Option<CalcLengthOrPercentage>>::from(*other);
|
||||
Ok(LengthOrPercentageOrNone::Calc(
|
||||
this.animate(&other, procedure)?.ok_or(())?,
|
||||
))
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToAnimatedZero for LengthOrPercentageOrNone {
|
||||
#[inline]
|
||||
fn to_animated_zero(&self) -> Result<Self, ()> {
|
||||
|
|
|
@ -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<Self, ()> {
|
||||
// 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<SquaredDistance, ()> {
|
||||
|
@ -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<Self, ()> {
|
||||
let this = <Option<CalcLengthOrPercentage>>::from(*self);
|
||||
let other = <Option<CalcLengthOrPercentage>>::from(*other);
|
||||
Ok(LengthOrPercentageOrAuto::Calc(
|
||||
this.animate(&other, procedure)?.ok_or(())?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl ComputeSquaredDistance for LengthOrPercentageOrAuto {
|
||||
#[inline]
|
||||
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
|
||||
|
@ -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<Self, ()> {
|
||||
let this = <Option<CalcLengthOrPercentage>>::from(*self);
|
||||
let other = <Option<CalcLengthOrPercentage>>::from(*other);
|
||||
Ok(LengthOrPercentageOrNone::Calc(
|
||||
this.animate(&other, procedure)?.ok_or(())?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl ComputeSquaredDistance for LengthOrPercentageOrNone {
|
||||
#[inline]
|
||||
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
|
||||
|
|
|
@ -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::<AnimateInputAttrs>(&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::<AnimateAttrs>(variant);
|
||||
if attrs.error {
|
||||
let variant_attrs = cg::parse_variant_attrs::<AnimationVariantAttrs>(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::<AnimateFieldAttrs>(&result.field);
|
||||
let field_attrs = cg::parse_field_attrs::<AnimationFieldAttrs>(&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<Path>,
|
||||
}
|
||||
|
||||
#[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,
|
||||
}
|
||||
|
|
|
@ -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<A>(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<A>(variant: &Variant) -> A
|
||||
where
|
||||
A: FromVariant,
|
||||
|
|
|
@ -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::<AnimateAttrs>(variant);
|
||||
let attrs = cg::parse_variant_attrs::<AnimationVariantAttrs>(variant);
|
||||
if attrs.error {
|
||||
append_error_clause = true;
|
||||
return None;
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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::<AnimateAttrs>(variant);
|
||||
let attrs = cg::parse_variant_attrs::<AnimationVariantAttrs>(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::<AnimateFieldAttrs>(&binding.field);
|
||||
let field_attrs = cg::parse_field_attrs::<AnimationFieldAttrs>(&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(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue