servo: Merge #17560 - Introduce ToAnimatedValue πŸŽ₯ (from servo:derive-all-the-things); r=<try>

Source-Repo: https://github.com/servo/servo
Source-Revision: 9a13cf6bdaa823369f29d7d0f4469087cf17ce6a

--HG--
extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear
extra : subtree_revision : 8e2354a1c6da7a5c78ed94e34be220fe8b8986c7
This commit is contained in:
Anthony Ramine 2017-06-29 06:49:39 -07:00
Π ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒ fd512fc09d
ΠšΠΎΠΌΠΌΠΈΡ‚ fd99f68571
10 ΠΈΠ·ΠΌΠ΅Π½Ρ‘Π½Π½Ρ‹Ρ… Ρ„Π°ΠΉΠ»ΠΎΠ²: 354 Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠΉ ΠΈ 219 ΡƒΠ΄Π°Π»Π΅Π½ΠΈΠΉ

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -110,6 +110,7 @@ macro_rules! define_keyword_type {
}
impl $crate::values::computed::ComputedValueAsSpecified for $name {}
impl $crate::values::animated::AnimatedValueAsComputed for $name {}
no_viewport_percentage!($name);
};
}

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -31,7 +31,10 @@ use std::cmp;
#[cfg(feature = "gecko")] use fnv::FnvHashMap;
use style_traits::ParseError;
use super::ComputedValues;
use values::{Auto, CSSFloat, CustomIdent, Either};
#[cfg(any(feature = "gecko", feature = "testing"))]
use values::Auto;
use values::{CSSFloat, CustomIdent, Either};
use values::animated::ToAnimatedValue;
use values::animated::effects::BoxShadowList as AnimatedBoxShadowList;
use values::animated::effects::Filter as AnimatedFilter;
use values::animated::effects::FilterList as AnimatedFilterList;
@ -408,7 +411,8 @@ impl AnimatedProperty {
};
% endif
% if not prop.is_animatable_with_computed_value:
let value: longhands::${prop.ident}::computed_value::T = value.into();
let value: longhands::${prop.ident}::computed_value::T =
ToAnimatedValue::from_animated_value(value);
% endif
style.mutate_${prop.style_struct.ident.strip("_")}().set_${prop.ident}(value);
}
@ -425,13 +429,21 @@ impl AnimatedProperty {
-> AnimatedProperty {
match *property {
% for prop in data.longhands:
% if prop.animatable:
AnimatableLonghand::${prop.camel_case} => {
AnimatedProperty::${prop.camel_case}(
old_style.get_${prop.style_struct.ident.strip("_")}().clone_${prop.ident}().into(),
new_style.get_${prop.style_struct.ident.strip("_")}().clone_${prop.ident}().into())
}
% endif
% if prop.animatable:
AnimatableLonghand::${prop.camel_case} => {
let old_computed = old_style.get_${prop.style_struct.ident.strip("_")}().clone_${prop.ident}();
let new_computed = new_style.get_${prop.style_struct.ident.strip("_")}().clone_${prop.ident}();
AnimatedProperty::${prop.camel_case}(
% if prop.is_animatable_with_computed_value:
old_computed,
new_computed,
% else:
old_computed.to_animated_value(),
new_computed.to_animated_value(),
% endif
)
}
% endif
% endfor
}
}
@ -492,7 +504,7 @@ impl AnimationValue {
% if prop.is_animatable_with_computed_value:
from
% else:
&from.clone().into()
&ToAnimatedValue::from_animated_value(from.clone())
% endif
))
% if prop.boxed:
@ -520,13 +532,14 @@ impl AnimationValue {
longhands::system_font::resolve_system_font(sf, context);
}
% endif
Some(AnimationValue::${prop.camel_case}(
% if prop.is_animatable_with_computed_value:
val.to_computed_value(context)
% else:
From::from(val.to_computed_value(context))
% endif
))
let computed = val.to_computed_value(context);
Some(AnimationValue::${prop.camel_case}(
% if prop.is_animatable_with_computed_value:
computed
% else:
computed.to_animated_value()
% endif
))
},
% endif
% endfor
@ -555,7 +568,7 @@ impl AnimationValue {
},
};
% if not prop.is_animatable_with_computed_value:
let computed = From::from(computed);
let computed = computed.to_animated_value();
% endif
Some(AnimationValue::${prop.camel_case}(computed))
},
@ -617,13 +630,16 @@ impl AnimationValue {
% for prop in data.longhands:
% if prop.animatable:
AnimatableLonghand::${prop.camel_case} => {
let computed = computed_values
.get_${prop.style_struct.ident.strip("_")}()
.clone_${prop.ident}();
AnimationValue::${prop.camel_case}(
% if prop.is_animatable_with_computed_value:
computed_values.get_${prop.style_struct.ident.strip("_")}().clone_${prop.ident}())
computed
% else:
From::from(computed_values.get_${prop.style_struct.ident.strip("_")}()
.clone_${prop.ident}()))
computed.to_animated_value()
% endif
)
}
% endif
% endfor
@ -2697,25 +2713,6 @@ impl<T, U> Animatable for Either<T, U>
}
}
impl From<IntermediateRGBA> for RGBA {
fn from(extended_rgba: IntermediateRGBA) -> RGBA {
// RGBA::from_floats clamps each component values.
RGBA::from_floats(extended_rgba.red,
extended_rgba.green,
extended_rgba.blue,
extended_rgba.alpha)
}
}
impl From<RGBA> for IntermediateRGBA {
fn from(rgba: RGBA) -> IntermediateRGBA {
IntermediateRGBA::new(rgba.red_f32(),
rgba.green_f32(),
rgba.blue_f32(),
rgba.alpha_f32())
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// Unlike RGBA, each component value may exceed the range [0.0, 1.0].
@ -2744,6 +2741,31 @@ impl IntermediateRGBA {
}
}
impl ToAnimatedValue for RGBA {
type AnimatedValue = IntermediateRGBA;
#[inline]
fn to_animated_value(self) -> Self::AnimatedValue {
IntermediateRGBA::new(
self.red_f32(),
self.green_f32(),
self.blue_f32(),
self.alpha_f32(),
)
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
// RGBA::from_floats clamps each component values.
RGBA::from_floats(
animated.red,
animated.green,
animated.blue,
animated.alpha,
)
}
}
/// Unlike Animatable for RGBA we don't clamp any component values.
impl Animatable for IntermediateRGBA {
#[inline]
@ -2798,24 +2820,6 @@ impl Animatable for IntermediateRGBA {
}
}
impl From<Either<Color, Auto>> for Either<IntermediateColor, Auto> {
fn from(from: Either<Color, Auto>) -> Either<IntermediateColor, Auto> {
match from {
Either::First(from) => Either::First(from.into()),
Either::Second(Auto) => Either::Second(Auto),
}
}
}
impl From<Either<IntermediateColor, Auto>> for Either<Color, Auto> {
fn from(from: Either<IntermediateColor, Auto>) -> Either<Color, Auto> {
match from {
Either::First(from) => Either::First(from.into()),
Either::Second(Auto) => Either::Second(Auto),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
@ -2856,6 +2860,26 @@ impl IntermediateColor {
}
}
impl ToAnimatedValue for Color {
type AnimatedValue = IntermediateColor;
#[inline]
fn to_animated_value(self) -> Self::AnimatedValue {
IntermediateColor {
color: self.color.to_animated_value(),
foreground_ratio: self.foreground_ratio as f32 * (1. / 255.),
}
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
Color {
color: RGBA::from_animated_value(animated.color),
foreground_ratio: (animated.foreground_ratio * 255.).round() as u8,
}
}
}
impl Animatable for IntermediateColor {
#[inline]
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
@ -2934,42 +2958,12 @@ impl Animatable for IntermediateColor {
}
}
impl From<Color> for IntermediateColor {
fn from(color: Color) -> IntermediateColor {
IntermediateColor {
color: color.color.into(),
foreground_ratio: color.foreground_ratio as f32 * (1. / 255.),
}
}
}
impl From<IntermediateColor> for Color {
fn from(color: IntermediateColor) -> Color {
Color {
color: color.color.into(),
foreground_ratio: (color.foreground_ratio * 255.).round() as u8,
}
}
}
/// Animatable SVGPaint
pub type IntermediateSVGPaint = SVGPaint<IntermediateRGBA>;
/// Animatable SVGPaintKind
pub type IntermediateSVGPaintKind = SVGPaintKind<IntermediateRGBA>;
impl From<::values::computed::SVGPaint> for IntermediateSVGPaint {
fn from(paint: ::values::computed::SVGPaint) -> IntermediateSVGPaint {
paint.convert(|color| (*color).into())
}
}
impl From<IntermediateSVGPaint> for ::values::computed::SVGPaint {
fn from(paint: IntermediateSVGPaint) -> ::values::computed::SVGPaint {
paint.convert(|color| (*color).into())
}
}
impl Animatable for IntermediateSVGPaint {
#[inline]
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -12,11 +12,8 @@ use properties::longhands::text_shadow::computed_value::T as ComputedTextShadowL
use std::cmp;
#[cfg(not(feature = "gecko"))]
use values::Impossible;
use values::animated::ToAnimatedValue;
use values::computed::{Angle, Number};
use values::computed::effects::BoxShadow as ComputedBoxShadow;
#[cfg(feature = "gecko")]
use values::computed::effects::Filter as ComputedFilter;
use values::computed::effects::SimpleShadow as ComputedSimpleShadow;
use values::computed::length::Length;
use values::generics::effects::BoxShadow as GenericBoxShadow;
use values::generics::effects::Filter as GenericFilter;
@ -51,15 +48,17 @@ pub struct TextShadowList(pub Vec<SimpleShadow>);
/// An animated value for the `drop-shadow()` filter.
pub type SimpleShadow = GenericSimpleShadow<IntermediateColor, Length, Length>;
impl From<BoxShadowList> for ComputedBoxShadowList {
fn from(list: BoxShadowList) -> Self {
ComputedBoxShadowList(list.0.into_iter().map(|s| s.into()).collect())
}
}
impl ToAnimatedValue for ComputedBoxShadowList {
type AnimatedValue = BoxShadowList;
impl From<ComputedBoxShadowList> for BoxShadowList {
fn from(list: ComputedBoxShadowList) -> Self {
BoxShadowList(list.0.into_iter().map(|s| s.into()).collect())
#[inline]
fn to_animated_value(self) -> Self::AnimatedValue {
BoxShadowList(self.0.to_animated_value())
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
ComputedBoxShadowList(ToAnimatedValue::from_animated_value(animated.0))
}
}
@ -114,15 +113,17 @@ impl Animatable for BoxShadowList {
}
}
impl From<TextShadowList> for ComputedTextShadowList {
fn from(list: TextShadowList) -> Self {
ComputedTextShadowList(list.0.into_iter().map(|s| s.into()).collect())
}
}
impl ToAnimatedValue for ComputedTextShadowList {
type AnimatedValue = TextShadowList;
impl From<ComputedTextShadowList> for TextShadowList {
fn from(list: ComputedTextShadowList) -> Self {
TextShadowList(list.0.into_iter().map(|s| s.into()).collect())
#[inline]
fn to_animated_value(self) -> Self::AnimatedValue {
TextShadowList(self.0.to_animated_value())
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
ComputedTextShadowList(ToAnimatedValue::from_animated_value(animated.0))
}
}
@ -170,28 +171,6 @@ impl Animatable for TextShadowList {
}
}
impl From<ComputedBoxShadow> for BoxShadow {
#[inline]
fn from(shadow: ComputedBoxShadow) -> Self {
BoxShadow {
base: shadow.base.into(),
spread: shadow.spread,
inset: shadow.inset,
}
}
}
impl From<BoxShadow> for ComputedBoxShadow {
#[inline]
fn from(shadow: BoxShadow) -> Self {
ComputedBoxShadow {
base: shadow.base.into(),
spread: shadow.spread,
inset: shadow.inset,
}
}
}
impl Animatable for BoxShadow {
#[inline]
fn add_weighted(
@ -227,99 +206,32 @@ impl Animatable for BoxShadow {
}
}
impl From<ComputedFilterList> for FilterList {
impl ToAnimatedValue for ComputedFilterList {
type AnimatedValue = FilterList;
#[cfg(not(feature = "gecko"))]
#[inline]
fn from(filters: ComputedFilterList) -> Self {
FilterList(filters.0)
fn to_animated_value(self) -> Self::AnimatedValue {
FilterList(self.0)
}
#[cfg(feature = "gecko")]
#[inline]
fn from(filters: ComputedFilterList) -> Self {
FilterList(filters.0.into_iter().map(|f| f.into()).collect())
fn to_animated_value(self) -> Self::AnimatedValue {
FilterList(self.0.to_animated_value())
}
}
impl From<FilterList> for ComputedFilterList {
#[cfg(not(feature = "gecko"))]
#[inline]
fn from(filters: FilterList) -> Self {
ComputedFilterList(filters.0)
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
ComputedFilterList(animated.0)
}
#[cfg(feature = "gecko")]
#[inline]
fn from(filters: FilterList) -> Self {
ComputedFilterList(filters.0.into_iter().map(|f| f.into()).collect())
}
}
#[cfg(feature = "gecko")]
impl From<ComputedFilter> for Filter {
#[inline]
fn from(filter: ComputedFilter) -> Self {
match filter {
GenericFilter::Blur(angle) => GenericFilter::Blur(angle),
GenericFilter::Brightness(factor) => GenericFilter::Brightness(factor),
GenericFilter::Contrast(factor) => GenericFilter::Contrast(factor),
GenericFilter::Grayscale(factor) => GenericFilter::Grayscale(factor),
GenericFilter::HueRotate(factor) => GenericFilter::HueRotate(factor),
GenericFilter::Invert(factor) => GenericFilter::Invert(factor),
GenericFilter::Opacity(factor) => GenericFilter::Opacity(factor),
GenericFilter::Saturate(factor) => GenericFilter::Saturate(factor),
GenericFilter::Sepia(factor) => GenericFilter::Sepia(factor),
GenericFilter::DropShadow(shadow) => {
GenericFilter::DropShadow(shadow.into())
},
GenericFilter::Url(url) => GenericFilter::Url(url),
}
}
}
#[cfg(feature = "gecko")]
impl From<Filter> for ComputedFilter {
#[inline]
fn from(filter: Filter) -> Self {
match filter {
GenericFilter::Blur(angle) => GenericFilter::Blur(angle),
GenericFilter::Brightness(factor) => GenericFilter::Brightness(factor),
GenericFilter::Contrast(factor) => GenericFilter::Contrast(factor),
GenericFilter::Grayscale(factor) => GenericFilter::Grayscale(factor),
GenericFilter::HueRotate(factor) => GenericFilter::HueRotate(factor),
GenericFilter::Invert(factor) => GenericFilter::Invert(factor),
GenericFilter::Opacity(factor) => GenericFilter::Opacity(factor),
GenericFilter::Saturate(factor) => GenericFilter::Saturate(factor),
GenericFilter::Sepia(factor) => GenericFilter::Sepia(factor),
GenericFilter::DropShadow(shadow) => {
GenericFilter::DropShadow(shadow.into())
},
GenericFilter::Url(url) => GenericFilter::Url(url.clone())
}
}
}
impl From<ComputedSimpleShadow> for SimpleShadow {
#[inline]
fn from(shadow: ComputedSimpleShadow) -> Self {
SimpleShadow {
color: shadow.color.into(),
horizontal: shadow.horizontal,
vertical: shadow.vertical,
blur: shadow.blur,
}
}
}
impl From<SimpleShadow> for ComputedSimpleShadow {
#[inline]
fn from(shadow: SimpleShadow) -> Self {
ComputedSimpleShadow {
color: shadow.color.into(),
horizontal: shadow.horizontal,
vertical: shadow.vertical,
blur: shadow.blur,
}
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
ComputedFilterList(ToAnimatedValue::from_animated_value(animated.0))
}
}

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -8,4 +8,83 @@
//! computed values and need yet another intermediate representation. This
//! module's raison d'Γͺtre is to ultimately contain all these types.
use app_units::Au;
use values::computed::Angle as ComputedAngle;
use values::specified::url::SpecifiedUrl;
pub mod effects;
/// Conversion between computed values and intermediate values for animations.
///
/// Notably, colors are represented as four floats during animations.
pub trait ToAnimatedValue {
/// The type of the animated value.
type AnimatedValue;
/// Converts this value to an animated value.
fn to_animated_value(self) -> Self::AnimatedValue;
/// Converts back an animated value into a computed value.
fn from_animated_value(animated: Self::AnimatedValue) -> Self;
}
impl<T> ToAnimatedValue for Option<T>
where
T: ToAnimatedValue,
{
type AnimatedValue = Option<<T as ToAnimatedValue>::AnimatedValue>;
#[inline]
fn to_animated_value(self) -> Self::AnimatedValue {
self.map(T::to_animated_value)
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
animated.map(T::from_animated_value)
}
}
impl<T> ToAnimatedValue for Vec<T>
where
T: ToAnimatedValue,
{
type AnimatedValue = Vec<<T as ToAnimatedValue>::AnimatedValue>;
#[inline]
fn to_animated_value(self) -> Self::AnimatedValue {
self.into_iter().map(T::to_animated_value).collect()
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
animated.into_iter().map(T::from_animated_value).collect()
}
}
/// Marker trait for computed values with the same representation during animations.
pub trait AnimatedValueAsComputed {}
impl AnimatedValueAsComputed for Au {}
impl AnimatedValueAsComputed for ComputedAngle {}
impl AnimatedValueAsComputed for SpecifiedUrl {}
impl AnimatedValueAsComputed for bool {}
impl AnimatedValueAsComputed for f32 {}
impl<T> ToAnimatedValue for T
where
T: AnimatedValueAsComputed,
{
type AnimatedValue = Self;
#[inline]
fn to_animated_value(self) -> Self {
self
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
animated
}
}

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -11,7 +11,7 @@ use values::specified::url::SpecifiedUrl;
/// A generic value for a single `box-shadow`.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Debug, HasViewportPercentage, PartialEq)]
#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToAnimatedValue)]
pub struct BoxShadow<Color, SizeLength, ShapeLength> {
/// The base shadow.
pub base: SimpleShadow<Color, SizeLength, ShapeLength>,
@ -23,7 +23,7 @@ pub struct BoxShadow<Color, SizeLength, ShapeLength> {
/// A generic value for a single `filter`.
#[cfg_attr(feature = "servo", derive(Deserialize, HeapSizeOf, Serialize))]
#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToComputedValue, ToCss)]
#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToAnimatedValue, ToComputedValue, ToCss)]
pub enum Filter<Angle, Factor, Length, DropShadow> {
/// `blur(<length>)`
#[css(function)]
@ -65,7 +65,7 @@ pub enum Filter<Angle, Factor, Length, DropShadow> {
/// Contrary to the canonical order from the spec, the color is serialised
/// first, like in Gecko and Webkit.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToCss)]
#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToAnimatedValue, ToCss)]
pub struct SimpleShadow<Color, SizeLength, ShapeLength> {
/// Color.
pub color: Color,

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -254,8 +254,8 @@ impl ToCss for FontSettingTagFloat {
/// An SVG paint value
///
/// https://www.w3.org/TR/SVG2/painting.html#SpecifyingPaint
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Debug, PartialEq, ToAnimatedValue)]
pub struct SVGPaint<ColorType> {
/// The paint source
pub kind: SVGPaintKind<ColorType>,
@ -269,7 +269,7 @@ pub struct SVGPaint<ColorType> {
/// to have a fallback, Gecko lets the context
/// properties have a fallback as well.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Debug, PartialEq, ToCss)]
#[derive(Clone, Debug, PartialEq, ToAnimatedValue, ToCss)]
pub enum SVGPaintKind<ColorType> {
/// `none`
None,

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -52,7 +52,7 @@ impl Parse for Impossible {
/// A struct representing one of two kinds of values.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Copy, HasViewportPercentage, PartialEq, ToComputedValue, ToCss)]
#[derive(Clone, Copy, HasViewportPercentage, PartialEq, ToAnimatedValue, ToComputedValue, ToCss)]
pub enum Either<A, B> {
/// The first value.
First(A),

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -10,6 +10,7 @@ extern crate synstructure;
use proc_macro::TokenStream;
mod has_viewport_percentage;
mod to_animated_value;
mod to_computed_value;
mod to_css;
@ -19,6 +20,12 @@ pub fn derive_has_viewport_percentage(stream: TokenStream) -> TokenStream {
has_viewport_percentage::derive(input).to_string().parse().unwrap()
}
#[proc_macro_derive(ToAnimatedValue)]
pub fn derive_to_animated_value(stream: TokenStream) -> TokenStream {
let input = syn::parse_derive_input(&stream.to_string()).unwrap();
to_animated_value::derive(input).to_string().parse().unwrap()
}
#[proc_macro_derive(ToComputedValue)]
pub fn derive_to_computed_value(stream: TokenStream) -> TokenStream {
let input = syn::parse_derive_input(&stream.to_string()).unwrap();

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -0,0 +1,141 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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 quote;
use syn;
use synstructure;
pub fn derive(input: syn::DeriveInput) -> quote::Tokens {
let name = &input.ident;
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(syn::Ty::Path(None, param.ident.clone().into()), None));
}
let animated_value_type = syn::Path::from(syn::PathSegment {
ident: name.clone(),
parameters: syn::PathParameters::AngleBracketed(syn::AngleBracketedParameterData {
lifetimes: input.generics.lifetimes.iter().map(|l| {
l.lifetime.clone()
}).collect(),
types: input.generics.ty_params.iter().map(|ty| {
syn::Ty::Path(
Some(syn::QSelf {
ty: Box::new(syn::Ty::Path(None, ty.ident.clone().into())),
position: 3,
}),
syn::Path {
global: true,
segments: vec![
"values".into(),
"animated".into(),
"ToAnimatedValue".into(),
"AnimatedValue".into(),
],
},
)
}).collect(),
.. Default::default()
}),
});
let to_body = match_body(&input, |field| {
quote!(::values::animated::ToAnimatedValue::to_animated_value(#field))
});
let from_body = match_body(&input, |field| {
quote!(::values::animated::ToAnimatedValue::from_animated_value(#field))
});
quote! {
impl #impl_generics ::values::animated::ToAnimatedValue for #name #ty_generics #where_clause {
type AnimatedValue = #animated_value_type;
#[allow(unused_variables)]
#[inline]
fn to_animated_value(self) -> Self::AnimatedValue {
match self {
#to_body
}
}
#[inline]
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
match animated {
#from_body
}
}
}
}
}
fn match_body<F>(input: &syn::DeriveInput, f: F) -> quote::Tokens
where
F: Fn(&synstructure::BindingInfo) -> quote::Tokens,
{
let by_value = synstructure::BindStyle::Move.into();
synstructure::each_variant(&input, &by_value, |fields, variant| {
let name = if let syn::Body::Enum(_) = input.body {
format!("{}::{}", input.ident, variant.ident).into()
} else {
variant.ident.clone()
};
let (animated_value, computed_fields) = synstructure::match_pattern(&name, &variant.data, &by_value);
let fields_pairs = fields.iter().zip(computed_fields.iter());
let mut computations = quote!();
computations.append_all(fields_pairs.map(|(field, computed_field)| {
let expr = f(field);
quote!(let #computed_field = #expr;)
}));
Some(quote!(
#computations
#animated_value
))
})
}
/// `#ty: ::values::animated::ToAnimatedValue<AnimatedValue = #animated_value,>`
fn where_predicate(ty: syn::Ty, animated_value: Option<syn::Ty>) -> syn::WherePredicate {
syn::WherePredicate::BoundPredicate(syn::WhereBoundPredicate {
bound_lifetimes: vec![],
bounded_ty: ty,
bounds: vec![syn::TyParamBound::Trait(
syn::PolyTraitRef {
bound_lifetimes: vec![],
trait_ref: trait_ref(animated_value),
},
syn::TraitBoundModifier::None
)],
})
}
/// `::values::animated::ToAnimatedValue<AnimatedValue = #animated_value,>`
fn trait_ref(animated_value: Option<syn::Ty>) -> syn::Path {
syn::Path {
global: true,
segments: vec![
"values".into(),
"animated".into(),
syn::PathSegment {
ident: "ToAnimatedValue".into(),
parameters: syn::PathParameters::AngleBracketed(
syn::AngleBracketedParameterData {
bindings: trait_bindings(animated_value),
.. Default::default()
}
),
}
],
}
}
/// `AnimatedValue = #animated_value,`
fn trait_bindings(animated_value: Option<syn::Ty>) -> Vec<syn::TypeBinding> {
animated_value.into_iter().map(|ty| {
syn::TypeBinding {
ident: "AnimatedValue".into(),
ty: ty,
}
}).collect()
}

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -7,12 +7,13 @@ use cssparser::RGBA;
use style::properties::animated_properties::{Animatable, IntermediateRGBA};
use style::properties::longhands::transform::computed_value::ComputedOperation as TransformOperation;
use style::properties::longhands::transform::computed_value::T as TransformList;
use style::values::animated::ToAnimatedValue;
use style::values::specified::length::Percentage;
fn interpolate_rgba(from: RGBA, to: RGBA, progress: f64) -> RGBA {
let from: IntermediateRGBA = from.into();
let to: IntermediateRGBA = to.into();
from.interpolate(&to, progress).unwrap().into()
let from = from.to_animated_value();
let to = to.to_animated_value();
RGBA::from_animated_value(from.interpolate(&to, progress).unwrap())
}
// Color