Auto merge of #17774 - servo:derive-all-the-things, r=emilio

Prepare some code for future derivation 🌊

<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/17774)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-07-19 01:56:05 -07:00 committed by GitHub
commit d76d097891
18 changed files with 402 additions and 251 deletions

View file

@ -129,6 +129,8 @@
% if animation_value_type == "ComputedValue":
use properties::animated_properties::Animatable;
use values::animated::ToAnimatedZero;
impl Animatable for T {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
-> Result<Self, ()> {
@ -149,6 +151,11 @@
self.0.compute_squared_distance(&other.0)
}
}
impl ToAnimatedZero for T {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
}
% endif
pub type Iter<'a, 'cx, 'cx_a> = ComputedVecIter<'a, 'cx, 'cx_a, super::single_value::SpecifiedValue>;

View file

@ -33,7 +33,7 @@ use super::ComputedValues;
#[cfg(any(feature = "gecko", feature = "testing"))]
use values::Auto;
use values::{CSSFloat, CustomIdent, Either};
use values::animated::ToAnimatedValue;
use values::animated::{ToAnimatedValue, ToAnimatedZero};
use values::animated::effects::BoxShadowList as AnimatedBoxShadowList;
use values::animated::effects::Filter as AnimatedFilter;
use values::animated::effects::FilterList as AnimatedFilterList;
@ -47,6 +47,49 @@ use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius;
use values::generics::effects::Filter;
use values::generics::position as generic_position;
/// A trait used to implement various procedures used during animation.
pub trait Animatable: Sized {
/// Performs a weighted sum of this value and |other|. This is used for
/// interpolation and addition of animation values.
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
-> Result<Self, ()>;
/// [Interpolates][interpolation] a value with another for a given property.
///
/// [interpolation]: https://w3c.github.io/web-animations/#animation-interpolation
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
self.add_weighted(other, 1.0 - progress, progress)
}
/// Returns the [sum][animation-addition] of this value and |other|.
///
/// [animation-addition]: https://w3c.github.io/web-animations/#animation-addition
fn add(&self, other: &Self) -> Result<Self, ()> {
self.add_weighted(other, 1.0, 1.0)
}
/// [Accumulates][animation-accumulation] this value onto itself (|count| - 1) times then
/// accumulates |other| onto the result.
/// If |count| is zero, the result will be |other|.
///
/// [animation-accumulation]: https://w3c.github.io/web-animations/#animation-accumulation
fn accumulate(&self, other: &Self, count: u64) -> Result<Self, ()> {
self.add_weighted(other, count as f64, 1.0)
}
/// Compute distance between a value and another for a given property.
fn compute_distance(&self, _other: &Self) -> Result<f64, ()> { Err(()) }
/// In order to compute the Euclidean distance of a list or property value with multiple
/// components, we need to compute squared distance for each element, so the vector can sum it
/// and then get its squared root as the distance.
fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> {
self.compute_distance(other).map(|d| d * d)
}
}
/// https://drafts.csswg.org/css-transitions/#animtype-repeatable-list
pub trait RepeatableListAnimatable: Animatable {}
/// A longhand property whose animation type is not "none".
///
@ -692,19 +735,6 @@ impl Animatable for AnimationValue {
}
}
fn get_zero_value(&self) -> Result<Self, ()> {
match *self {
% for prop in data.longhands:
% if prop.animatable and prop.animation_value_type != "discrete":
AnimationValue::${prop.camel_case}(ref base) => {
Ok(AnimationValue::${prop.camel_case}(base.get_zero_value()?))
},
% endif
% endfor
_ => Err(()),
}
}
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
match (self, other) {
% for prop in data.longhands:
@ -730,61 +760,22 @@ impl Animatable for AnimationValue {
}
}
/// A trait used to implement various procedures used during animation.
pub trait Animatable: Sized {
/// Performs a weighted sum of this value and |other|. This is used for
/// interpolation and addition of animation values.
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
-> Result<Self, ()>;
/// [Interpolates][interpolation] a value with another for a given property.
///
/// [interpolation]: https://w3c.github.io/web-animations/#animation-interpolation
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
self.add_weighted(other, 1.0 - progress, progress)
}
/// Returns the [sum][animation-addition] of this value and |other|.
///
/// [animation-addition]: https://w3c.github.io/web-animations/#animation-addition
fn add(&self, other: &Self) -> Result<Self, ()> {
self.add_weighted(other, 1.0, 1.0)
}
/// [Accumulates][animation-accumulation] this value onto itself (|count| - 1) times then
/// accumulates |other| onto the result.
/// If |count| is zero, the result will be |other|.
///
/// [animation-accumulation]: https://w3c.github.io/web-animations/#animation-accumulation
fn accumulate(&self, other: &Self, count: u64) -> Result<Self, ()> {
self.add_weighted(other, count as f64, 1.0)
}
/// Returns a value that, when added with an underlying value, will produce the underlying
/// value. This is used for SMIL animation's "by-animation" where SMIL first interpolates from
/// the zero value to the 'by' value, and then adds the result to the underlying value.
///
/// This is not the necessarily the same as the initial value of a property. For example, the
/// initial value of 'stroke-width' is 1, but the zero value is 0, since adding 1 to the
/// underlying value will not produce the underlying value.
impl ToAnimatedZero for AnimationValue {
#[inline]
fn get_zero_value(&self) -> Result<Self, ()> { Err(()) }
/// Compute distance between a value and another for a given property.
fn compute_distance(&self, _other: &Self) -> Result<f64, ()> { Err(()) }
/// In order to compute the Euclidean distance of a list or property value with multiple
/// components, we need to compute squared distance for each element, so the vector can sum it
/// and then get its squared root as the distance.
fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> {
self.compute_distance(other).map(|d| d * d)
fn to_animated_zero(&self) -> Result<Self, ()> {
match *self {
% for prop in data.longhands:
% if prop.animatable and prop.animation_value_type != "discrete":
AnimationValue::${prop.camel_case}(ref base) => {
Ok(AnimationValue::${prop.camel_case}(base.to_animated_zero()?))
},
% endif
% endfor
_ => Err(()),
}
}
}
/// https://drafts.csswg.org/css-transitions/#animtype-repeatable-list
pub trait RepeatableListAnimatable: Animatable {}
impl RepeatableListAnimatable for LengthOrPercentage {}
impl RepeatableListAnimatable for Either<f32, LengthOrPercentage> {}
@ -834,9 +825,6 @@ impl Animatable for Au {
Ok(Au((self.0 as f64 * self_portion + other.0 as f64 * other_portion).round() as i32))
}
#[inline]
fn get_zero_value(&self) -> Result<Self, ()> { Ok(Au(0)) }
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
self.0.compute_distance(&other.0)
@ -887,9 +875,6 @@ impl Animatable for f32 {
Ok((*self as f64 * self_portion + *other as f64 * other_portion) as f32)
}
#[inline]
fn get_zero_value(&self) -> Result<Self, ()> { Ok(0.) }
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
Ok((*self - *other).abs() as f64)
@ -903,9 +888,6 @@ impl Animatable for f64 {
Ok(*self * self_portion + *other * other_portion)
}
#[inline]
fn get_zero_value(&self) -> Result<Self, ()> { Ok(0.) }
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
Ok((*self - *other).abs())
@ -919,9 +901,6 @@ impl Animatable for i32 {
Ok((*self as f64 * self_portion + *other as f64 * other_portion).round() as i32)
}
#[inline]
fn get_zero_value(&self) -> Result<Self, ()> { Ok(0) }
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
Ok((*self - *other).abs() as f64)
@ -956,15 +935,19 @@ impl Animatable for Percentage {
Ok(Percentage((self.0 as f64 * self_portion + other.0 as f64 * other_portion) as f32))
}
#[inline]
fn get_zero_value(&self) -> Result<Self, ()> { Ok(Percentage(0.)) }
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
Ok((self.0 as f64 - other.0 as f64).abs())
}
}
impl ToAnimatedZero for Percentage {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
Ok(Percentage(0.))
}
}
/// https://drafts.csswg.org/css-transitions/#animtype-visibility
impl Animatable for Visibility {
#[inline]
@ -990,6 +973,13 @@ impl Animatable for Visibility {
}
}
impl ToAnimatedZero for Visibility {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
Err(())
}
}
impl<T: Animatable + Copy> Animatable for Size2D<T> {
#[inline]
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
@ -1028,6 +1018,11 @@ impl Animatable for BorderCornerRadius {
}
}
impl ToAnimatedZero for BorderCornerRadius {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
}
/// https://drafts.csswg.org/css-transitions/#animtype-length
impl Animatable for VerticalAlign {
#[inline]
@ -1055,6 +1050,11 @@ impl Animatable for VerticalAlign {
}
}
impl ToAnimatedZero for VerticalAlign {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
}
/// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
impl Animatable for CalcLengthOrPercentage {
#[inline]
@ -1125,11 +1125,6 @@ impl Animatable for LengthOrPercentage {
}
}
#[inline]
fn get_zero_value(&self) -> Result<Self, ()> {
Ok(LengthOrPercentage::zero())
}
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
match (*self, *other) {
@ -1173,6 +1168,13 @@ impl Animatable for LengthOrPercentage {
}
}
impl ToAnimatedZero for LengthOrPercentage {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
Ok(LengthOrPercentage::zero())
}
}
/// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
impl Animatable for LengthOrPercentageOrAuto {
#[inline]
@ -1202,18 +1204,6 @@ impl Animatable for LengthOrPercentageOrAuto {
}
}
#[inline]
fn get_zero_value(&self) -> Result<Self, ()> {
match *self {
LengthOrPercentageOrAuto::Length(_) |
LengthOrPercentageOrAuto::Percentage(_) |
LengthOrPercentageOrAuto::Calc(_) => {
Ok(LengthOrPercentageOrAuto::Length(Au(0)))
},
LengthOrPercentageOrAuto::Auto => Err(()),
}
}
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
match (*self, *other) {
@ -1262,6 +1252,20 @@ impl Animatable for LengthOrPercentageOrAuto {
}
}
impl ToAnimatedZero for LengthOrPercentageOrAuto {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
match *self {
LengthOrPercentageOrAuto::Length(_) |
LengthOrPercentageOrAuto::Percentage(_) |
LengthOrPercentageOrAuto::Calc(_) => {
Ok(LengthOrPercentageOrAuto::Length(Au(0)))
},
LengthOrPercentageOrAuto::Auto => Err(()),
}
}
}
/// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
impl Animatable for LengthOrPercentageOrNone {
#[inline]
@ -1291,18 +1295,6 @@ impl Animatable for LengthOrPercentageOrNone {
}
}
#[inline]
fn get_zero_value(&self) -> Result<Self, ()> {
match *self {
LengthOrPercentageOrNone::Length(_) |
LengthOrPercentageOrNone::Percentage(_) |
LengthOrPercentageOrNone::Calc(_) => {
Ok(LengthOrPercentageOrNone::Length(Au(0)))
},
LengthOrPercentageOrNone::None => Err(()),
}
}
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
match (*self, *other) {
@ -1324,6 +1316,20 @@ impl Animatable for LengthOrPercentageOrNone {
}
}
impl ToAnimatedZero for LengthOrPercentageOrNone {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
match *self {
LengthOrPercentageOrNone::Length(_) |
LengthOrPercentageOrNone::Percentage(_) |
LengthOrPercentageOrNone::Calc(_) => {
Ok(LengthOrPercentageOrNone::Length(Au(0)))
},
LengthOrPercentageOrNone::None => Err(()),
}
}
}
/// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
impl Animatable for MozLength {
#[inline]
@ -1350,6 +1356,11 @@ impl Animatable for MozLength {
}
}
impl ToAnimatedZero for MozLength {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
}
/// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
impl Animatable for MaxLength {
#[inline]
@ -1376,6 +1387,11 @@ impl Animatable for MaxLength {
}
}
impl ToAnimatedZero for MaxLength {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
}
/// http://dev.w3.org/csswg/css-transitions/#animtype-font-weight
impl Animatable for FontWeight {
#[inline]
@ -1388,9 +1404,6 @@ impl Animatable for FontWeight {
Ok(FontWeight(weight as u16))
}
#[inline]
fn get_zero_value(&self) -> Result<Self, ()> { Ok(FontWeight::normal()) }
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
let a = self.0 as f64;
@ -1399,6 +1412,13 @@ impl Animatable for FontWeight {
}
}
impl ToAnimatedZero for FontWeight {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
Ok(FontWeight::normal())
}
}
/// https://drafts.csswg.org/css-fonts/#font-stretch-prop
impl Animatable for FontStretch {
#[inline]
@ -1422,6 +1442,11 @@ impl Animatable for FontStretch {
}
}
impl ToAnimatedZero for FontStretch {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
}
/// We should treat font stretch as real number in order to interpolate this property.
/// https://drafts.csswg.org/css-fonts-3/#font-stretch-animation
impl From<FontStretch> for f64 {
@ -1462,14 +1487,6 @@ impl<H: Animatable, V: Animatable> Animatable for generic_position::Position<H,
})
}
#[inline]
fn get_zero_value(&self) -> Result<Self, ()> {
Ok(generic_position::Position {
horizontal: self.horizontal.get_zero_value()?,
vertical: self.vertical.get_zero_value()?,
})
}
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
self.compute_squared_distance(other).map(|sd| sd.sqrt())
@ -1482,6 +1499,20 @@ impl<H: Animatable, V: Animatable> Animatable for generic_position::Position<H,
}
}
impl<H, V> ToAnimatedZero for generic_position::Position<H, V>
where
H: ToAnimatedZero,
V: ToAnimatedZero,
{
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
Ok(generic_position::Position {
horizontal: self.horizontal.to_animated_zero()?,
vertical: self.vertical.to_animated_zero()?,
})
}
}
impl<H, V> RepeatableListAnimatable for generic_position::Position<H, V>
where H: RepeatableListAnimatable, V: RepeatableListAnimatable {}
@ -1515,6 +1546,11 @@ impl Animatable for ClipRect {
}
}
impl ToAnimatedZero for ClipRect {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
}
/// Check if it's possible to do a direct numerical interpolation
/// between these two transform lists.
/// http://dev.w3.org/csswg/css-transforms/#transform-transform-animation
@ -2589,9 +2625,13 @@ impl Animatable for TransformList {
}
}
}
}
impl ToAnimatedZero for TransformList {
#[inline]
fn get_zero_value(&self) -> Result<Self, ()> { Ok(TransformList(None)) }
fn to_animated_zero(&self) -> Result<Self, ()> {
Ok(TransformList(None))
}
}
impl<T, U> Animatable for Either<T, U>
@ -2613,18 +2653,6 @@ impl<T, U> Animatable for Either<T, U>
}
}
#[inline]
fn get_zero_value(&self) -> Result<Self, ()> {
match *self {
Either::First(ref this) => {
Ok(Either::First(this.get_zero_value()?))
},
Either::Second(ref this) => {
Ok(Either::Second(this.get_zero_value()?))
},
}
}
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
match (self, other) {
@ -2652,6 +2680,24 @@ impl<T, U> Animatable for Either<T, U>
}
}
impl<A, B> ToAnimatedZero for Either<A, B>
where
A: ToAnimatedZero,
B: ToAnimatedZero,
{
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
match *self {
Either::First(ref first) => {
Ok(Either::First(first.to_animated_zero()?))
},
Either::Second(ref second) => {
Ok(Either::Second(second.to_animated_zero()?))
},
}
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// Unlike RGBA, each component value may exceed the range [0.0, 1.0].
@ -2730,11 +2776,6 @@ impl Animatable for IntermediateRGBA {
}
}
#[inline]
fn get_zero_value(&self) -> Result<Self, ()> {
Ok(IntermediateRGBA::transparent())
}
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
self.compute_squared_distance(other).map(|sq| sq.sqrt())
@ -2759,6 +2800,13 @@ impl Animatable for IntermediateRGBA {
}
}
impl ToAnimatedZero for IntermediateRGBA {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
Ok(IntermediateRGBA::transparent())
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
@ -2897,6 +2945,11 @@ impl Animatable for IntermediateColor {
}
}
impl ToAnimatedZero for IntermediateColor {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
}
/// Animatable SVGPaint
pub type IntermediateSVGPaint = SVGPaint<IntermediateRGBA>;
@ -2922,12 +2975,14 @@ impl Animatable for IntermediateSVGPaint {
Ok(self.kind.compute_squared_distance(&other.kind)? +
self.fallback.compute_squared_distance(&other.fallback)?)
}
}
impl ToAnimatedZero for IntermediateSVGPaint {
#[inline]
fn get_zero_value(&self) -> Result<Self, ()> {
fn to_animated_zero(&self) -> Result<Self, ()> {
Ok(IntermediateSVGPaint {
kind: self.kind.get_zero_value()?,
fallback: self.fallback.and_then(|v| v.get_zero_value().ok()),
kind: self.kind.to_animated_zero()?,
fallback: self.fallback.and_then(|v| v.to_animated_zero().ok()),
})
}
}
@ -2960,12 +3015,14 @@ impl Animatable for IntermediateSVGPaintKind {
_ => Err(())
}
}
}
impl ToAnimatedZero for IntermediateSVGPaintKind {
#[inline]
fn get_zero_value(&self) -> Result<Self, ()> {
fn to_animated_zero(&self) -> Result<Self, ()> {
match *self {
SVGPaintKind::Color(ref color) => {
Ok(SVGPaintKind::Color(color.get_zero_value()?))
Ok(SVGPaintKind::Color(color.to_animated_zero()?))
},
SVGPaintKind::None |
SVGPaintKind::ContextFill |

View file

@ -1044,6 +1044,7 @@ ${helpers.single_keyword_system("font-variant-caps",
pub mod computed_value {
use properties::animated_properties::Animatable;
use values::CSSFloat;
use values::animated::ToAnimatedZero;
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Copy, Clone, Debug, PartialEq, ToCss)]
@ -1081,6 +1082,11 @@ ${helpers.single_keyword_system("font-variant-caps",
}
}
}
impl ToAnimatedZero for T {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
}
}
#[inline]

View file

@ -28,6 +28,7 @@ ${helpers.single_keyword("caption-side", "top bottom",
pub mod computed_value {
use app_units::Au;
use properties::animated_properties::Animatable;
use values::animated::ToAnimatedZero;
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Copy, Debug, PartialEq, ToCss)]
@ -60,6 +61,11 @@ ${helpers.single_keyword("caption-side", "top bottom",
self.vertical.compute_squared_distance(&other.vertical)?)
}
}
impl ToAnimatedZero for T {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
}
}
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]