Introduce ToAnimatedValue 🎥

This commit is contained in:
Anthony Ramine 2017-06-29 13:35:40 +02:00
parent 522d24d126
commit 9ab0b9b4ac
10 changed files with 354 additions and 219 deletions

View file

@ -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);
};
}

View file

@ -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
@ -2698,25 +2714,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].
@ -2745,6 +2742,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]
@ -2799,24 +2821,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)]
@ -2857,6 +2861,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, ()> {
@ -2935,42 +2959,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, ()> {

View file

@ -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))
}
}

View file

@ -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
}
}

View file

@ -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,

View file

@ -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,

View file

@ -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),