Rewrite interpolate() in terms of a more general add_weighted() function

Generalizing the procedure like this will allow us to re-use it for addition of
most types.
This commit is contained in:
Brian Birtles 2017-05-15 12:26:21 +09:00
parent 8366b4d4f9
commit 2f07b29296
7 changed files with 261 additions and 200 deletions

View file

@ -113,8 +113,9 @@
% if delegate_animate:
use properties::animated_properties::Animatable;
impl Animatable for T {
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
self.0.interpolate(&other.0, progress).map(T)
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
-> Result<Self, ()> {
self.0.add_weighted(&other.0, self_portion, other_portion).map(T)
}
#[inline]
@ -976,16 +977,17 @@
<%def name="impl_animatable_for_option_tuple(value_for_none)">
impl Animatable for T {
#[inline]
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
-> Result<Self, ()> {
match (self, other) {
(&T(Some(ref this)), &T(Some(ref other))) => {
Ok(T(this.interpolate(other, progress).ok()))
Ok(T(this.add_weighted(other, self_portion, other_portion).ok()))
},
(&T(Some(ref this)), &T(None)) => {
Ok(T(this.interpolate(&${value_for_none}, progress).ok()))
Ok(T(this.add_weighted(&${value_for_none}, self_portion, other_portion).ok()))
},
(&T(None), &T(Some(ref other))) => {
Ok(T(${value_for_none}.interpolate(other, progress).ok()))
Ok(T(${value_for_none}.add_weighted(other, self_portion, other_portion).ok()))
},
(&T(None), &T(None)) => {
Ok(T(None))

View file

@ -581,27 +581,28 @@ impl AnimationValue {
}
impl Animatable for AnimationValue {
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
-> Result<Self, ()> {
match (self, other) {
% for prop in data.longhands:
% if prop.animatable:
(&AnimationValue::${prop.camel_case}(ref from),
&AnimationValue::${prop.camel_case}(ref to)) => {
// https://w3c.github.io/web-animations/#discrete-animation-type
% if prop.animation_value_type == "discrete":
if progress < 0.5 {
if self_portion > other_portion {
Ok(AnimationValue::${prop.camel_case}(*from))
} else {
Ok(AnimationValue::${prop.camel_case}(*to))
}
% else:
from.interpolate(to, progress).map(AnimationValue::${prop.camel_case})
from.add_weighted(to, self_portion, other_portion)
.map(AnimationValue::${prop.camel_case})
% endif
}
% endif
% endfor
_ => {
panic!("Expected interpolation of computed values of the same \
panic!("Expected weighted addition of computed values of the same \
property, got: {:?}, {:?}", self, other);
}
}
@ -635,10 +636,17 @@ 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, ()>;
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
self.add_weighted(other, 1.0 - progress, progress)
}
/// Compute distance between a value and another for a given property.
fn compute_distance(&self, _other: &Self) -> Result<f64, ()> { Err(()) }
@ -658,11 +666,12 @@ impl RepeatableListAnimatable for LengthOrPercentage {}
impl RepeatableListAnimatable for Either<f32, LengthOrPercentage> {}
impl<T: RepeatableListAnimatable> Animatable for SmallVec<[T; 1]> {
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
-> Result<Self, ()> {
use num_integer::lcm;
let len = lcm(self.len(), other.len());
self.iter().cycle().zip(other.iter().cycle()).take(len).map(|(me, you)| {
me.interpolate(you, progress)
me.add_weighted(you, self_portion, other_portion)
}).collect()
}
@ -684,8 +693,8 @@ impl<T: RepeatableListAnimatable> Animatable for SmallVec<[T; 1]> {
/// https://drafts.csswg.org/css-transitions/#animtype-number
impl Animatable for Au {
#[inline]
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
Ok(Au((self.0 as f64 + (other.0 as f64 - self.0 as f64) * progress).round() as i32))
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
Ok(Au((self.0 as f64 * self_portion + other.0 as f64 * other_portion).round() as i32))
}
#[inline]
@ -698,10 +707,10 @@ impl <T> Animatable for Option<T>
where T: Animatable,
{
#[inline]
fn interpolate(&self, other: &Option<T>, progress: f64) -> Result<Option<T>, ()> {
fn add_weighted(&self, other: &Option<T>, self_portion: f64, other_portion: f64) -> Result<Option<T>, ()> {
match (self, other) {
(&Some(ref this), &Some(ref other)) => {
Ok(this.interpolate(other, progress).ok())
Ok(this.add_weighted(other, self_portion, other_portion).ok())
}
_ => Err(()),
}
@ -731,8 +740,8 @@ impl <T> Animatable for Option<T>
/// https://drafts.csswg.org/css-transitions/#animtype-number
impl Animatable for f32 {
#[inline]
fn interpolate(&self, other: &f32, progress: f64) -> Result<Self, ()> {
Ok(((*self as f64) + ((*other as f64) - (*self as f64)) * progress) as f32)
fn add_weighted(&self, other: &f32, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
Ok((*self as f64 * self_portion + *other as f64 * other_portion) as f32)
}
#[inline]
@ -744,8 +753,8 @@ impl Animatable for f32 {
/// https://drafts.csswg.org/css-transitions/#animtype-number
impl Animatable for f64 {
#[inline]
fn interpolate(&self, other: &f64, progress: f64) -> Result<Self, ()> {
Ok(*self + (*other - *self) * progress)
fn add_weighted(&self, other: &f64, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
Ok(*self * self_portion + *other * other_portion)
}
#[inline]
@ -757,10 +766,8 @@ impl Animatable for f64 {
/// https://drafts.csswg.org/css-transitions/#animtype-integer
impl Animatable for i32 {
#[inline]
fn interpolate(&self, other: &i32, progress: f64) -> Result<Self, ()> {
let a = *self as f64;
let b = *other as f64;
Ok((a + (b - a) * progress).round() as i32)
fn add_weighted(&self, other: &i32, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
Ok((*self as f64 * self_portion + *other as f64 * other_portion).round() as i32)
}
#[inline]
@ -772,20 +779,23 @@ impl Animatable for i32 {
/// https://drafts.csswg.org/css-transitions/#animtype-number
impl Animatable for Angle {
#[inline]
fn interpolate(&self, other: &Angle, progress: f64) -> Result<Self, ()> {
self.radians().interpolate(&other.radians(), progress).map(Angle::from_radians)
fn add_weighted(&self, other: &Angle, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
self.radians()
.add_weighted(&other.radians(), self_portion, other_portion)
.map(Angle::from_radians)
}
}
/// https://drafts.csswg.org/css-transitions/#animtype-visibility
impl Animatable for Visibility {
#[inline]
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
match (*self, *other) {
(Visibility::visible, _) | (_, Visibility::visible) => {
Ok(if progress >= 0.0 && progress <= 1.0 {
Ok(if self_portion >= 0.0 && self_portion <= 1.0 &&
other_portion >= 0.0 && other_portion <= 1.0 {
Visibility::visible
} else if progress < 0.0 {
} else if self_portion > other_portion {
*self
} else {
*other
@ -807,9 +817,9 @@ impl Animatable for Visibility {
impl<T: Animatable + Copy> Animatable for Size2D<T> {
#[inline]
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
let width = try!(self.width.interpolate(&other.width, progress));
let height = try!(self.height.interpolate(&other.height, progress));
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
let width = try!(self.width.add_weighted(&other.width, self_portion, other_portion));
let height = try!(self.height.add_weighted(&other.height, self_portion, other_portion));
Ok(Size2D::new(width, height))
}
@ -817,9 +827,9 @@ impl<T: Animatable + Copy> Animatable for Size2D<T> {
impl<T: Animatable + Copy> Animatable for Point2D<T> {
#[inline]
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
let x = try!(self.x.interpolate(&other.x, progress));
let y = try!(self.y.interpolate(&other.y, progress));
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
let x = try!(self.x.add_weighted(&other.x, self_portion, other_portion));
let y = try!(self.y.add_weighted(&other.y, self_portion, other_portion));
Ok(Point2D::new(x, y))
}
@ -827,8 +837,8 @@ impl<T: Animatable + Copy> Animatable for Point2D<T> {
impl Animatable for BorderRadiusSize {
#[inline]
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
self.0.interpolate(&other.0, progress).map(generics::BorderRadiusSize)
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
self.0.add_weighted(&other.0, self_portion, other_portion).map(generics::BorderRadiusSize)
}
#[inline]
@ -846,11 +856,11 @@ impl Animatable for BorderRadiusSize {
/// https://drafts.csswg.org/css-transitions/#animtype-length
impl Animatable for VerticalAlign {
#[inline]
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
match (*self, *other) {
(VerticalAlign::LengthOrPercentage(LengthOrPercentage::Length(ref this)),
VerticalAlign::LengthOrPercentage(LengthOrPercentage::Length(ref other))) => {
this.interpolate(other, progress).map(|value| {
this.add_weighted(other, self_portion, other_portion).map(|value| {
VerticalAlign::LengthOrPercentage(LengthOrPercentage::Length(value))
})
}
@ -872,8 +882,8 @@ impl Animatable for VerticalAlign {
impl Animatable for BackgroundSizeList {
#[inline]
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
self.0.interpolate(&other.0, progress).map(BackgroundSizeList)
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
self.0.add_weighted(&other.0, self_portion, other_portion).map(BackgroundSizeList)
}
#[inline]
@ -890,24 +900,28 @@ impl Animatable for BackgroundSizeList {
/// https://drafts.csswg.org/css-transitions/#animtype-color
impl Animatable for RGBA {
#[inline]
fn interpolate(&self, other: &RGBA, progress: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &RGBA, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
fn clamp(val: f32) -> f32 {
val.max(0.).min(1.)
}
let alpha = clamp(try!(self.alpha_f32().interpolate(&other.alpha_f32(), progress)));
let alpha = clamp(try!(self.alpha_f32().add_weighted(&other.alpha_f32(),
self_portion, other_portion)));
if alpha == 0. {
Ok(RGBA::transparent())
} else {
// NB: We rely on RGBA::from_floats clamping already.
let red = try!((self.red_f32() * self.alpha_f32())
.interpolate(&(other.red_f32() * other.alpha_f32()), progress))
.add_weighted(&(other.red_f32() * other.alpha_f32()),
self_portion, other_portion))
* 1. / alpha;
let green = try!((self.green_f32() * self.alpha_f32())
.interpolate(&(other.green_f32() * other.alpha_f32()), progress))
.add_weighted(&(other.green_f32() * other.alpha_f32()),
self_portion, other_portion))
* 1. / alpha;
let blue = try!((self.blue_f32() * self.alpha_f32())
.interpolate(&(other.blue_f32() * other.alpha_f32()), progress))
.add_weighted(&(other.blue_f32() * other.alpha_f32()),
self_portion, other_portion))
* 1. / alpha;
Ok(RGBA::from_floats(red, green, blue, alpha))
}
@ -948,10 +962,10 @@ impl Animatable for RGBA {
/// https://drafts.csswg.org/css-transitions/#animtype-color
impl Animatable for CSSParserColor {
#[inline]
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
match (*self, *other) {
(CSSParserColor::RGBA(ref this), CSSParserColor::RGBA(ref other)) => {
this.interpolate(other, progress).map(CSSParserColor::RGBA)
this.add_weighted(other, self_portion, other_portion).map(CSSParserColor::RGBA)
}
_ => Err(()),
}
@ -976,10 +990,11 @@ impl Animatable for CSSParserColor {
/// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
impl Animatable for CalcLengthOrPercentage {
#[inline]
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
fn interpolate_half<T>(this: Option<T>,
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
fn add_weighted_half<T>(this: Option<T>,
other: Option<T>,
progress: f64)
self_portion: f64,
other_portion: f64)
-> Result<Option<T>, ()>
where T: Default + Animatable,
{
@ -988,14 +1003,15 @@ impl Animatable for CalcLengthOrPercentage {
(this, other) => {
let this = this.unwrap_or(T::default());
let other = other.unwrap_or(T::default());
this.interpolate(&other, progress).map(Some)
this.add_weighted(&other, self_portion, other_portion).map(Some)
}
}
}
Ok(CalcLengthOrPercentage {
length: try!(self.length.interpolate(&other.length, progress)),
percentage: try!(interpolate_half(self.percentage, other.percentage, progress)),
length: try!(self.length.add_weighted(&other.length, self_portion, other_portion)),
percentage: try!(add_weighted_half(self.percentage, other.percentage,
self_portion, other_portion)),
})
}
@ -1015,20 +1031,22 @@ impl Animatable for CalcLengthOrPercentage {
/// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
impl Animatable for LengthOrPercentage {
#[inline]
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
match (*self, *other) {
(LengthOrPercentage::Length(ref this),
LengthOrPercentage::Length(ref other)) => {
this.interpolate(other, progress).map(LengthOrPercentage::Length)
this.add_weighted(other, self_portion, other_portion)
.map(LengthOrPercentage::Length)
}
(LengthOrPercentage::Percentage(ref this),
LengthOrPercentage::Percentage(ref other)) => {
this.interpolate(other, progress).map(LengthOrPercentage::Percentage)
this.add_weighted(other, self_portion, other_portion)
.map(LengthOrPercentage::Percentage)
}
(this, other) => {
let this: CalcLengthOrPercentage = From::from(this);
let other: CalcLengthOrPercentage = From::from(other);
this.interpolate(&other, progress)
this.add_weighted(&other, self_portion, other_portion)
.map(LengthOrPercentage::Calc)
}
}
@ -1080,15 +1098,17 @@ impl Animatable for LengthOrPercentage {
/// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
impl Animatable for LengthOrPercentageOrAuto {
#[inline]
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
match (*self, *other) {
(LengthOrPercentageOrAuto::Length(ref this),
LengthOrPercentageOrAuto::Length(ref other)) => {
this.interpolate(other, progress).map(LengthOrPercentageOrAuto::Length)
this.add_weighted(other, self_portion, other_portion)
.map(LengthOrPercentageOrAuto::Length)
}
(LengthOrPercentageOrAuto::Percentage(ref this),
LengthOrPercentageOrAuto::Percentage(ref other)) => {
this.interpolate(other, progress).map(LengthOrPercentageOrAuto::Percentage)
this.add_weighted(other, self_portion, other_portion)
.map(LengthOrPercentageOrAuto::Percentage)
}
(LengthOrPercentageOrAuto::Auto, LengthOrPercentageOrAuto::Auto) => {
Ok(LengthOrPercentageOrAuto::Auto)
@ -1096,7 +1116,7 @@ impl Animatable for LengthOrPercentageOrAuto {
(this, other) => {
let this: Option<CalcLengthOrPercentage> = From::from(this);
let other: Option<CalcLengthOrPercentage> = From::from(other);
match this.interpolate(&other, progress) {
match this.add_weighted(&other, self_portion, other_portion) {
Ok(Some(result)) => Ok(LengthOrPercentageOrAuto::Calc(result)),
_ => Err(()),
}
@ -1155,15 +1175,17 @@ impl Animatable for LengthOrPercentageOrAuto {
/// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
impl Animatable for LengthOrPercentageOrNone {
#[inline]
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
match (*self, *other) {
(LengthOrPercentageOrNone::Length(ref this),
LengthOrPercentageOrNone::Length(ref other)) => {
this.interpolate(other, progress).map(LengthOrPercentageOrNone::Length)
this.add_weighted(other, self_portion, other_portion)
.map(LengthOrPercentageOrNone::Length)
}
(LengthOrPercentageOrNone::Percentage(ref this),
LengthOrPercentageOrNone::Percentage(ref other)) => {
this.interpolate(other, progress).map(LengthOrPercentageOrNone::Percentage)
this.add_weighted(other, self_portion, other_portion)
.map(LengthOrPercentageOrNone::Percentage)
}
(LengthOrPercentageOrNone::None, LengthOrPercentageOrNone::None) => {
Ok(LengthOrPercentageOrNone::None)
@ -1191,11 +1213,12 @@ impl Animatable for LengthOrPercentageOrNone {
/// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
impl Animatable for MinLength {
#[inline]
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
match (*self, *other) {
(MinLength::LengthOrPercentage(ref this),
MinLength::LengthOrPercentage(ref other)) => {
this.interpolate(other, progress).map(MinLength::LengthOrPercentage)
this.add_weighted(other, self_portion, other_portion)
.map(MinLength::LengthOrPercentage)
}
_ => Err(()),
}
@ -1216,11 +1239,12 @@ impl Animatable for MinLength {
/// https://drafts.csswg.org/css-transitions/#animtype-lpcalc
impl Animatable for MaxLength {
#[inline]
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
match (*self, *other) {
(MaxLength::LengthOrPercentage(ref this),
MaxLength::LengthOrPercentage(ref other)) => {
this.interpolate(other, progress).map(MaxLength::LengthOrPercentage)
this.add_weighted(other, self_portion, other_portion)
.map(MaxLength::LengthOrPercentage)
}
_ => Err(()),
}
@ -1242,15 +1266,15 @@ impl Animatable for MaxLength {
/// https://drafts.csswg.org/css-transitions/#animtype-length
impl Animatable for LineHeight {
#[inline]
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
match (*self, *other) {
(LineHeight::Length(ref this),
LineHeight::Length(ref other)) => {
this.interpolate(other, progress).map(LineHeight::Length)
this.add_weighted(other, self_portion, other_portion).map(LineHeight::Length)
}
(LineHeight::Number(ref this),
LineHeight::Number(ref other)) => {
this.interpolate(other, progress).map(LineHeight::Number)
this.add_weighted(other, self_portion, other_portion).map(LineHeight::Number)
}
(LineHeight::Normal, LineHeight::Normal) => {
Ok(LineHeight::Normal)
@ -1278,10 +1302,10 @@ impl Animatable for LineHeight {
/// http://dev.w3.org/csswg/css-transitions/#animtype-font-weight
impl Animatable for FontWeight {
#[inline]
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
let a = (*self as u32) as f64;
let b = (*other as u32) as f64;
let weight = a + (b - a) * progress;
let weight = a * self_portion + b * other_portion;
Ok(if weight < 150. {
FontWeight::Weight100
} else if weight < 250. {
@ -1314,10 +1338,12 @@ impl Animatable for FontWeight {
/// https://drafts.csswg.org/css-transitions/#animtype-simple-list
impl<H: Animatable, V: Animatable> Animatable for generic_position::Position<H, V> {
#[inline]
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
Ok(generic_position::Position {
horizontal: try!(self.horizontal.interpolate(&other.horizontal, progress)),
vertical: try!(self.vertical.interpolate(&other.vertical, progress)),
horizontal: try!(self.horizontal.add_weighted(&other.horizontal,
self_portion, other_portion)),
vertical: try!(self.vertical.add_weighted(&other.vertical,
self_portion, other_portion)),
})
}
@ -1339,12 +1365,13 @@ impl<H, V> RepeatableListAnimatable for generic_position::Position<H, V>
/// https://drafts.csswg.org/css-transitions/#animtype-rect
impl Animatable for ClipRect {
#[inline]
fn interpolate(&self, other: &Self, time: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
-> Result<Self, ()> {
Ok(ClipRect {
top: try!(self.top.interpolate(&other.top, time)),
right: try!(self.right.interpolate(&other.right, time)),
bottom: try!(self.bottom.interpolate(&other.bottom, time)),
left: try!(self.left.interpolate(&other.left, time)),
top: try!(self.top.add_weighted(&other.top, self_portion, other_portion)),
right: try!(self.right.add_weighted(&other.right, self_portion, other_portion)),
bottom: try!(self.bottom.add_weighted(&other.bottom, self_portion, other_portion)),
left: try!(self.left.add_weighted(&other.left, self_portion, other_portion)),
})
}
@ -1366,7 +1393,7 @@ impl Animatable for ClipRect {
<%def name="impl_animatable_for_shadow(item, transparent_color)">
impl Animatable for ${item} {
#[inline]
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
% if "Box" in item:
// It can't be interpolated if inset does not match.
if self.inset != other.inset {
@ -1374,12 +1401,14 @@ impl Animatable for ClipRect {
}
% endif
let x = try!(self.offset_x.interpolate(&other.offset_x, progress));
let y = try!(self.offset_y.interpolate(&other.offset_y, progress));
let color = try!(self.color.interpolate(&other.color, progress));
let blur = try!(self.blur_radius.interpolate(&other.blur_radius, progress));
let x = try!(self.offset_x.add_weighted(&other.offset_x, self_portion, other_portion));
let y = try!(self.offset_y.add_weighted(&other.offset_y, self_portion, other_portion));
let color = try!(self.color.add_weighted(&other.color, self_portion, other_portion));
let blur = try!(self.blur_radius.add_weighted(&other.blur_radius,
self_portion, other_portion));
% if "Box" in item:
let spread = try!(self.spread_radius.interpolate(&other.spread_radius, progress));
let spread = try!(self.spread_radius.add_weighted(&other.spread_radius,
self_portion, other_portion));
% endif
Ok(${item} {
@ -1421,7 +1450,7 @@ impl Animatable for ClipRect {
/// https://drafts.csswg.org/css-transitions/#animtype-shadow-list
impl Animatable for ${item}List {
#[inline]
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
// The inset value must change
% if "Box" in item:
let mut zero = ${item} {
@ -1449,18 +1478,18 @@ impl Animatable for ClipRect {
for i in 0..max_len {
let shadow = match (self.0.get(i), other.0.get(i)) {
(Some(shadow), Some(other))
=> try!(shadow.interpolate(other, progress)),
=> try!(shadow.add_weighted(other, self_portion, other_portion)),
(Some(shadow), None) => {
% if "Box" in item:
zero.inset = shadow.inset;
% endif
shadow.interpolate(&zero, progress).unwrap()
shadow.add_weighted(&zero, self_portion, other_portion).unwrap()
}
(None, Some(shadow)) => {
% if "Box" in item:
zero.inset = shadow.inset;
% endif
zero.interpolate(&shadow, progress).unwrap()
zero.add_weighted(&shadow, self_portion, other_portion).unwrap()
}
(None, None) => unreachable!(),
};
@ -1541,11 +1570,12 @@ fn build_identity_transform_list(list: &[TransformOperation]) -> Vec<TransformOp
result
}
/// Interpolate two transform lists.
/// Add two transform lists.
/// http://dev.w3.org/csswg/css-transforms/#interpolation-of-transforms
fn interpolate_transform_list(from_list: &[TransformOperation],
fn add_weighted_transform_lists(from_list: &[TransformOperation],
to_list: &[TransformOperation],
progress: f64) -> TransformList {
self_portion: f64,
other_portion: f64) -> TransformList {
let mut result = vec![];
if can_interpolate_list(from_list, to_list) {
@ -1553,33 +1583,33 @@ fn interpolate_transform_list(from_list: &[TransformOperation],
match (from, to) {
(&TransformOperation::Matrix(from),
&TransformOperation::Matrix(_to)) => {
let interpolated = from.interpolate(&_to, progress).unwrap();
result.push(TransformOperation::Matrix(interpolated));
let sum = from.add_weighted(&_to, self_portion, other_portion).unwrap();
result.push(TransformOperation::Matrix(sum));
}
(&TransformOperation::MatrixWithPercents(_),
&TransformOperation::MatrixWithPercents(_)) => {
// We don't interpolate `-moz-transform` matrices yet.
// We don't add_weighted `-moz-transform` matrices yet.
// They contain percentage values.
{}
}
(&TransformOperation::Skew(fx, fy),
&TransformOperation::Skew(tx, ty)) => {
let ix = fx.interpolate(&tx, progress).unwrap();
let iy = fy.interpolate(&ty, progress).unwrap();
let ix = fx.add_weighted(&tx, self_portion, other_portion).unwrap();
let iy = fy.add_weighted(&ty, self_portion, other_portion).unwrap();
result.push(TransformOperation::Skew(ix, iy));
}
(&TransformOperation::Translate(fx, fy, fz),
&TransformOperation::Translate(tx, ty, tz)) => {
let ix = fx.interpolate(&tx, progress).unwrap();
let iy = fy.interpolate(&ty, progress).unwrap();
let iz = fz.interpolate(&tz, progress).unwrap();
let ix = fx.add_weighted(&tx, self_portion, other_portion).unwrap();
let iy = fy.add_weighted(&ty, self_portion, other_portion).unwrap();
let iz = fz.add_weighted(&tz, self_portion, other_portion).unwrap();
result.push(TransformOperation::Translate(ix, iy, iz));
}
(&TransformOperation::Scale(fx, fy, fz),
&TransformOperation::Scale(tx, ty, tz)) => {
let ix = fx.interpolate(&tx, progress).unwrap();
let iy = fy.interpolate(&ty, progress).unwrap();
let iz = fz.interpolate(&tz, progress).unwrap();
let ix = fx.add_weighted(&tx, self_portion, other_portion).unwrap();
let iy = fy.add_weighted(&ty, self_portion, other_portion).unwrap();
let iz = fz.add_weighted(&tz, self_portion, other_portion).unwrap();
result.push(TransformOperation::Scale(ix, iy, iz));
}
(&TransformOperation::Rotate(fx, fy, fz, fa),
@ -1589,14 +1619,15 @@ fn interpolate_transform_list(from_list: &[TransformOperation],
let (fx, fy, fz) = (fx / norm_f, fy / norm_f, fz / norm_f);
let (tx, ty, tz) = (tx / norm_t, ty / norm_t, tz / norm_t);
if fx == tx && fy == ty && fz == tz {
let ia = fa.interpolate(&ta, progress).unwrap();
let ia = fa.add_weighted(&ta, self_portion, other_portion).unwrap();
result.push(TransformOperation::Rotate(fx, fy, fz, ia));
} else {
let matrix_f = rotate_to_matrix(fx, fy, fz, fa);
let matrix_t = rotate_to_matrix(tx, ty, tz, ta);
let interpolated = matrix_f.interpolate(&matrix_t, progress).unwrap();
let sum = matrix_f.add_weighted(&matrix_t, self_portion, other_portion)
.unwrap();
result.push(TransformOperation::Matrix(interpolated));
result.push(TransformOperation::Matrix(sum));
}
}
(&TransformOperation::Perspective(fd),
@ -1605,8 +1636,9 @@ fn interpolate_transform_list(from_list: &[TransformOperation],
let mut td_matrix = ComputedMatrix::identity();
fd_matrix.m43 = -1. / fd.to_f32_px();
td_matrix.m43 = -1. / _td.to_f32_px();
let interpolated = fd_matrix.interpolate(&td_matrix, progress).unwrap();
result.push(TransformOperation::Matrix(interpolated));
let sum = fd_matrix.add_weighted(&td_matrix, self_portion, other_portion)
.unwrap();
result.push(TransformOperation::Matrix(sum));
}
_ => {
// This should be unreachable due to the can_interpolate_list() call.
@ -1685,37 +1717,37 @@ pub struct MatrixDecomposed2D {
}
impl Animatable for InnerMatrix2D {
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
Ok(InnerMatrix2D {
m11: try!(self.m11.interpolate(&other.m11, progress)),
m12: try!(self.m12.interpolate(&other.m12, progress)),
m21: try!(self.m21.interpolate(&other.m21, progress)),
m22: try!(self.m22.interpolate(&other.m22, progress)),
m11: try!(self.m11.add_weighted(&other.m11, self_portion, other_portion)),
m12: try!(self.m12.add_weighted(&other.m12, self_portion, other_portion)),
m21: try!(self.m21.add_weighted(&other.m21, self_portion, other_portion)),
m22: try!(self.m22.add_weighted(&other.m22, self_portion, other_portion)),
})
}
}
impl Animatable for Translate2D {
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
Ok(Translate2D(
try!(self.0.interpolate(&other.0, progress)),
try!(self.1.interpolate(&other.1, progress))
try!(self.0.add_weighted(&other.0, self_portion, other_portion)),
try!(self.1.add_weighted(&other.1, self_portion, other_portion))
))
}
}
impl Animatable for Scale2D {
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
Ok(Scale2D(
try!(self.0.interpolate(&other.0, progress)),
try!(self.1.interpolate(&other.1, progress))
try!(self.0.add_weighted(&other.0, self_portion, other_portion)),
try!(self.1.add_weighted(&other.1, self_portion, other_portion))
))
}
}
impl Animatable for MatrixDecomposed2D {
/// https://drafts.csswg.org/css-transforms/#interpolation-of-decomposed-2d-matrix-values
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
// If x-axis of one is flipped, and y-axis of the other,
// convert to an unflipped rotation.
let mut scale = self.scale;
@ -1745,10 +1777,11 @@ impl Animatable for MatrixDecomposed2D {
}
// Interpolate all values.
let translate = try!(self.translate.interpolate(&other.translate, progress));
let scale = try!(scale.interpolate(&other.scale, progress));
let angle = try!(angle.interpolate(&other_angle, progress));
let matrix = try!(self.matrix.interpolate(&other.matrix, progress));
let translate = try!(self.translate.add_weighted(&other.translate,
self_portion, other_portion));
let scale = try!(scale.add_weighted(&other.scale, self_portion, other_portion));
let angle = try!(angle.add_weighted(&other_angle, self_portion, other_portion));
let matrix = try!(self.matrix.add_weighted(&other.matrix, self_portion, other_portion));
Ok(MatrixDecomposed2D {
translate: translate,
@ -1760,25 +1793,26 @@ impl Animatable for MatrixDecomposed2D {
}
impl Animatable for ComputedMatrix {
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
if self.is_3d() || other.is_3d() {
let decomposed_from = decompose_3d_matrix(*self);
let decomposed_to = decompose_3d_matrix(*other);
match (decomposed_from, decomposed_to) {
(Ok(from), Ok(to)) => {
let interpolated = try!(from.interpolate(&to, progress));
Ok(ComputedMatrix::from(interpolated))
let sum = try!(from.add_weighted(&to, self_portion, other_portion));
Ok(ComputedMatrix::from(sum))
},
_ => {
let interpolated = if progress < 0.5 {*self} else {*other};
Ok(interpolated)
let result = if self_portion > other_portion {*self} else {*other};
Ok(result)
}
}
} else {
let decomposed_from = MatrixDecomposed2D::from(*self);
let decomposed_to = MatrixDecomposed2D::from(*other);
let interpolated = try!(decomposed_from.interpolate(&decomposed_to, progress));
Ok(ComputedMatrix::from(interpolated))
let sum = try!(decomposed_from.add_weighted(&decomposed_to,
self_portion, other_portion));
Ok(ComputedMatrix::from(sum))
}
}
}
@ -2094,58 +2128,64 @@ fn cross(row1: [f32; 3], row2: [f32; 3]) -> [f32; 3] {
}
impl Animatable for Translate3D {
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
Ok(Translate3D(
try!(self.0.interpolate(&other.0, progress)),
try!(self.1.interpolate(&other.1, progress)),
try!(self.2.interpolate(&other.2, progress))
try!(self.0.add_weighted(&other.0, self_portion, other_portion)),
try!(self.1.add_weighted(&other.1, self_portion, other_portion)),
try!(self.2.add_weighted(&other.2, self_portion, other_portion))
))
}
}
impl Animatable for Scale3D {
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
Ok(Scale3D(
try!(self.0.interpolate(&other.0, progress)),
try!(self.1.interpolate(&other.1, progress)),
try!(self.2.interpolate(&other.2, progress))
try!(self.0.add_weighted(&other.0, self_portion, other_portion)),
try!(self.1.add_weighted(&other.1, self_portion, other_portion)),
try!(self.2.add_weighted(&other.2, self_portion, other_portion))
))
}
}
impl Animatable for Skew {
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
Ok(Skew(
try!(self.0.interpolate(&other.0, progress)),
try!(self.1.interpolate(&other.1, progress)),
try!(self.2.interpolate(&other.2, progress))
try!(self.0.add_weighted(&other.0, self_portion, other_portion)),
try!(self.1.add_weighted(&other.1, self_portion, other_portion)),
try!(self.2.add_weighted(&other.2, self_portion, other_portion))
))
}
}
impl Animatable for Perspective {
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
Ok(Perspective(
try!(self.0.interpolate(&other.0, progress)),
try!(self.1.interpolate(&other.1, progress)),
try!(self.2.interpolate(&other.2, progress)),
try!(self.3.interpolate(&other.3, progress))
try!(self.0.add_weighted(&other.0, self_portion, other_portion)),
try!(self.1.add_weighted(&other.1, self_portion, other_portion)),
try!(self.2.add_weighted(&other.2, self_portion, other_portion)),
try!(self.3.add_weighted(&other.3, self_portion, other_portion))
))
}
}
impl Animatable for MatrixDecomposed3D {
/// https://drafts.csswg.org/css-transforms/#interpolation-of-decomposed-3d-matrix-values
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
let mut interpolated = *self;
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
-> Result<Self, ()> {
assert!(self_portion + other_portion == 1.0f64,
"add_weighted should only be used for interpolating transforms");
// Interpolate translate, scale, skew and perspective components.
interpolated.translate = try!(self.translate.interpolate(&other.translate, progress));
interpolated.scale = try!(self.scale.interpolate(&other.scale, progress));
interpolated.skew = try!(self.skew.interpolate(&other.skew, progress));
interpolated.perspective = try!(self.perspective.interpolate(&other.perspective, progress));
let mut sum = *self;
// Interpolate quaternions using spherical linear interpolation (Slerp).
// Add translate, scale, skew and perspective components.
sum.translate = try!(self.translate.add_weighted(&other.translate,
self_portion, other_portion));
sum.scale = try!(self.scale.add_weighted(&other.scale, self_portion, other_portion));
sum.skew = try!(self.skew.add_weighted(&other.skew, self_portion, other_portion));
sum.perspective = try!(self.perspective.add_weighted(&other.perspective,
self_portion, other_portion));
// Add quaternions using spherical linear interpolation (Slerp).
let mut product = self.quaternion.0 * other.quaternion.0 +
self.quaternion.1 * other.quaternion.1 +
self.quaternion.2 * other.quaternion.2 +
@ -2156,21 +2196,21 @@ impl Animatable for MatrixDecomposed3D {
product = product.max(-1.0);
if product == 1.0 {
return Ok(interpolated);
return Ok(sum);
}
let theta = product.acos();
let w = (progress as f32 * theta).sin() * 1.0 / (1.0 - product * product).sqrt();
let w = (other_portion as f32 * theta).sin() * 1.0 / (1.0 - product * product).sqrt();
let mut a = *self;
let mut b = *other;
% for i in range(4):
a.quaternion.${i} *= (progress as f32 * theta).cos() - product * w;
a.quaternion.${i} *= (other_portion as f32 * theta).cos() - product * w;
b.quaternion.${i} *= w;
interpolated.quaternion.${i} = a.quaternion.${i} + b.quaternion.${i};
sum.quaternion.${i} = a.quaternion.${i} + b.quaternion.${i};
% endfor
Ok(interpolated)
Ok(sum)
}
}
@ -2374,22 +2414,22 @@ impl ComputedMatrix {
/// https://drafts.csswg.org/css-transforms/#interpolation-of-transforms
impl Animatable for TransformList {
#[inline]
fn interpolate(&self, other: &TransformList, progress: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &TransformList, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
// http://dev.w3.org/csswg/css-transforms/#interpolation-of-transforms
let result = match (&self.0, &other.0) {
(&Some(ref from_list), &Some(ref to_list)) => {
// Two lists of transforms
interpolate_transform_list(from_list, &to_list, progress)
add_weighted_transform_lists(from_list, &to_list, self_portion, other_portion)
}
(&Some(ref from_list), &None) => {
// http://dev.w3.org/csswg/css-transforms/#none-transform-animation
let to_list = build_identity_transform_list(from_list);
interpolate_transform_list(from_list, &to_list, progress)
add_weighted_transform_lists(from_list, &to_list, self_portion, other_portion)
}
(&None, &Some(ref to_list)) => {
// http://dev.w3.org/csswg/css-transforms/#none-transform-animation
let from_list = build_identity_transform_list(to_list);
interpolate_transform_list(&from_list, to_list, progress)
add_weighted_transform_lists(&from_list, to_list, self_portion, other_portion)
}
_ => {
// http://dev.w3.org/csswg/css-transforms/#none-none-animation
@ -2405,17 +2445,17 @@ impl<T, U> Animatable for Either<T, U>
where T: Animatable + Copy, U: Animatable + Copy,
{
#[inline]
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
match (*self, *other) {
(Either::First(ref this), Either::First(ref other)) => {
this.interpolate(&other, progress).map(Either::First)
this.add_weighted(&other, self_portion, other_portion).map(Either::First)
},
(Either::Second(ref this), Either::Second(ref other)) => {
this.interpolate(&other, progress).map(Either::Second)
this.add_weighted(&other, self_portion, other_portion).map(Either::Second)
},
_ => {
let interpolated = if progress < 0.5 { *self } else { *other };
Ok(interpolated)
let result = if self_portion > other_portion {*self} else {*other};
Ok(result)
}
}
}
@ -2497,21 +2537,26 @@ impl IntermediateRGBA {
/// Unlike Animatable for RGBA we don't clamp any component values.
impl Animatable for IntermediateRGBA {
#[inline]
fn interpolate(&self, other: &IntermediateRGBA, progress: f64) -> Result<Self, ()> {
let alpha = try!(self.alpha.interpolate(&other.alpha, progress));
if alpha == 0. {
fn add_weighted(&self, other: &IntermediateRGBA, self_portion: f64, other_portion: f64)
-> Result<Self, ()> {
let mut alpha = try!(self.alpha.add_weighted(&other.alpha, self_portion, other_portion));
if alpha <= 0. {
// Ideally we should return color value that only alpha component is
// 0, but this is what current gecko does.
Ok(IntermediateRGBA::transparent())
} else {
alpha = alpha.min(1.);
let red = try!((self.red * self.alpha)
.interpolate(&(other.red * other.alpha), progress))
.add_weighted(&(other.red * other.alpha),
self_portion, other_portion))
* 1. / alpha;
let green = try!((self.green * self.alpha)
.interpolate(&(other.green * other.alpha), progress))
.add_weighted(&(other.green * other.alpha),
self_portion, other_portion))
* 1. / alpha;
let blue = try!((self.blue * self.alpha)
.interpolate(&(other.blue * other.alpha), progress))
.add_weighted(&(other.blue * other.alpha),
self_portion, other_portion))
* 1. / alpha;
Ok(IntermediateRGBA::new(red, green, blue, alpha))
}
@ -2588,10 +2633,12 @@ pub enum IntermediateColor {
impl Animatable for IntermediateColor {
#[inline]
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
match (*self, *other) {
(IntermediateColor::IntermediateRGBA(ref this), IntermediateColor::IntermediateRGBA(ref other)) => {
this.interpolate(other, progress).map(IntermediateColor::IntermediateRGBA)
(IntermediateColor::IntermediateRGBA(ref this),
IntermediateColor::IntermediateRGBA(ref other)) => {
this.add_weighted(other, self_portion, other_portion)
.map(IntermediateColor::IntermediateRGBA)
}
// FIXME: Bug 1345709: Implement currentColor animations.
_ => Err(()),

View file

@ -190,13 +190,16 @@ ${helpers.single_keyword("background-origin",
impl RepeatableListAnimatable for T {}
impl Animatable for T {
fn interpolate(&self, other: &Self, time: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
-> Result<Self, ()> {
use properties::longhands::background_size::single_value::computed_value::ExplicitSize;
match (self, other) {
(&T::Explicit(ref me), &T::Explicit(ref other)) => {
Ok(T::Explicit(ExplicitSize {
width: try!(me.width.interpolate(&other.width, time)),
height: try!(me.height.interpolate(&other.height, time)),
width: try!(me.width.add_weighted(&other.width,
self_portion, other_portion)),
height: try!(me.height.add_weighted(&other.height,
self_portion, other_portion)),
}))
}
_ => Err(()),

View file

@ -2198,11 +2198,14 @@ ${helpers.single_keyword("transform-style",
impl Animatable for T {
#[inline]
fn interpolate(&self, other: &Self, time: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
-> Result<Self, ()> {
Ok(T {
horizontal: try!(self.horizontal.interpolate(&other.horizontal, time)),
vertical: try!(self.vertical.interpolate(&other.vertical, time)),
depth: try!(self.depth.interpolate(&other.depth, time)),
horizontal: try!(self.horizontal.add_weighted(&other.horizontal,
self_portion, other_portion)),
vertical: try!(self.vertical.add_weighted(&other.vertical,
self_portion, other_portion)),
depth: try!(self.depth.add_weighted(&other.depth, self_portion, other_portion)),
})
}

View file

@ -1073,10 +1073,12 @@ ${helpers.single_keyword_system("font-variant-caps",
}
impl Animatable for T {
fn interpolate(&self, other: &Self, time: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
-> Result<Self, ()> {
match (*self, *other) {
(T::Number(ref number), T::Number(ref other)) =>
Ok(T::Number(try!(number.interpolate(other, time)))),
Ok(T::Number(try!(number.add_weighted(other,
self_portion, other_portion)))),
_ => Err(()),
}
}

View file

@ -42,10 +42,13 @@ ${helpers.single_keyword("caption-side", "top bottom",
/// https://drafts.csswg.org/css-transitions/#animtype-simple-list
impl Animatable for T {
#[inline]
fn interpolate(&self, other: &Self, time: f64) -> Result<Self, ()> {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
-> Result<Self, ()> {
Ok(T {
horizontal: try!(self.horizontal.interpolate(&other.horizontal, time)),
vertical: try!(self.vertical.interpolate(&other.vertical, time)),
horizontal: try!(self.horizontal.add_weighted(&other.horizontal,
self_portion, other_portion)),
vertical: try!(self.vertical.add_weighted(&other.vertical,
self_portion, other_portion)),
})
}

View file

@ -129,7 +129,8 @@ macro_rules! define_keyword_type {
impl Animatable for $name {
#[inline]
fn interpolate(&self, _other: &Self, _progress: f64) -> Result<Self, ()> {
fn add_weighted(&self, _other: &Self, _self_progress: f64, _other_progress: f64)
-> Result<Self, ()> {
Ok($name)
}
}