--- a/servo/components/style/properties/helpers/animated_properties.mako.rs
+++ b/servo/components/style/properties/helpers/animated_properties.mako.rs
@@ -576,37 +576,38 @@ impl AnimationValue {
% endif
% endfor
ref other => panic!("Can't use TransitionProperty::{:?} here.", other),
}
}
}
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);
}
}
}
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
match (self, other) {
% for prop in data.longhands:
@@ -630,20 +631,27 @@ 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(()) }
/// 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, ()> {
@@ -653,21 +661,22 @@ pub trait Animatable: Sized {
/// https://drafts.csswg.org/css-transitions/#animtype-repeatable-list
pub trait RepeatableListAnimatable: Animatable {}
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()
}
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
self.compute_squared_distance(other).map(|sd| sd.sqrt())
}
@@ -679,34 +688,34 @@ impl<T: RepeatableListAnimatable> Animat
me.compute_squared_distance(you)
}).collect::<Result<Vec<_>, _>>().map(|d| d.iter().sum())
}
}
/// 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]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
self.0.compute_distance(&other.0)
}
}
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(()),
}
}
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
match (self, other) {
@@ -726,71 +735,72 @@ impl <T> Animatable for Option<T>
_ => Err(()),
}
}
}
/// 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]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
Ok((*self - *other).abs() as f64)
}
}
/// 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]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
Ok((*self - *other).abs())
}
}
/// 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]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
Ok((*self - *other).abs() as f64)
}
}
/// 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
})
}
_ => Err(()),
}
}
@@ -802,38 +812,38 @@ impl Animatable for Visibility {
} else {
Ok(1.0)
}
}
}
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))
}
}
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))
}
}
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]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
self.compute_squared_distance(other).map(|sd| sd.sqrt())
}
#[inline]
@@ -841,21 +851,21 @@ impl Animatable for BorderRadiusSize {
Ok(try!(self.0.width.compute_squared_distance(&other.0.width)) +
try!(self.0.height.compute_squared_distance(&other.0.height)))
}
}
/// 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))
})
}
_ => Err(()),
}
}
#[inline]
@@ -867,52 +877,56 @@ impl Animatable for VerticalAlign {
},
_ => Err(()),
}
}
}
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]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
self.0.compute_distance(&other.0)
}
#[inline]
fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> {
self.0.compute_squared_distance(&other.0)
}
}
/// 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))
}
}
/// https://www.w3.org/TR/smil-animation/#animateColorElement says we should use Euclidean
/// RGB-cube distance.
#[inline]
@@ -943,20 +957,20 @@ impl Animatable for RGBA {
});
Ok(diff)
}
}
/// 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(()),
}
}
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
self.compute_squared_distance(other).map(|sq| sq.sqrt())
@@ -971,36 +985,38 @@ impl Animatable for CSSParserColor {
_ => Ok(0.0),
}
}
}
/// 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>,
- other: Option<T>,
- progress: f64)
- -> Result<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>,
+ self_portion: f64,
+ other_portion: f64)
+ -> Result<Option<T>, ()>
where T: Default + Animatable,
{
match (this, other) {
(None, None) => Ok(None),
(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)),
})
}
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
self.compute_squared_distance(other).map(|sq| sq.sqrt())
}
@@ -1010,30 +1026,32 @@ impl Animatable for CalcLengthOrPercenta
let percentage_diff = (self.percentage() - other.percentage()) as f64;
Ok(length_diff * length_diff + percentage_diff * percentage_diff)
}
}
/// 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)
}
}
}
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
match (*self, *other) {
@@ -1075,33 +1093,35 @@ 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)
}
(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(()),
}
}
}
}
#[inline]
@@ -1150,25 +1170,27 @@ impl Animatable for LengthOrPercentageOr
}
}
}
}
/// 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)
}
_ => Err(())
}
}
@@ -1186,21 +1208,22 @@ impl Animatable for LengthOrPercentageOr
_ => Err(())
}
}
}
/// 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(()),
}
}
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
match (*self, *other) {
@@ -1211,21 +1234,22 @@ impl Animatable for MinLength {
_ => Err(()),
}
}
}
/// 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(()),
}
}
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
match (*self, *other) {
@@ -1237,25 +1261,25 @@ impl Animatable for MaxLength {
}
}
}
/// https://drafts.csswg.org/css-transitions/#animtype-number
/// 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)
}
_ => Err(()),
}
}
@@ -1273,20 +1297,20 @@ impl Animatable for LineHeight {
_ => Err(()),
}
}
}
/// 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. {
FontWeight::Weight200
} else if weight < 350. {
FontWeight::Weight300
} else if weight < 450. {
FontWeight::Weight400
@@ -1309,20 +1333,22 @@ impl Animatable for FontWeight {
let b = (*other as u32) as f64;
a.compute_distance(&b)
}
}
/// 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)),
})
}
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
self.compute_squared_distance(other).map(|sd| sd.sqrt())
}
@@ -1334,22 +1360,23 @@ impl<H: Animatable, V: Animatable> Anima
}
impl<H, V> RepeatableListAnimatable for generic_position::Position<H, V>
where H: RepeatableListAnimatable, V: RepeatableListAnimatable {}
/// 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)),
})
}
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
self.compute_squared_distance(other).map(|sd| sd.sqrt())
}
@@ -1361,30 +1388,32 @@ impl Animatable for ClipRect {
try!(self.left.compute_distance(&other.left)) ];
Ok(list.iter().fold(0.0f64, |sum, diff| sum + diff * diff))
}
}
<%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 {
return Err(());
}
% 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} {
offset_x: x,
offset_y: y,
blur_radius: blur,
color: color,
% if "Box" in item:
@@ -1416,17 +1445,17 @@ impl Animatable for ClipRect {
];
Ok(list.iter().fold(0.0f64, |sum, diff| sum + diff * diff))
}
}
/// 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} {
% else:
let zero = ${item} {
% endif
offset_x: Au(0),
offset_y: Au(0),
@@ -1444,28 +1473,28 @@ impl Animatable for ClipRect {
SmallVec::from_vec(Vec::with_capacity(max_len))
} else {
SmallVec::new()
};
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!(),
};
result.push(shadow);
}
Ok(${item}List(result))
}
@@ -1536,82 +1565,85 @@ fn build_identity_transform_list(list: &
result.push(TransformOperation::Matrix(identity));
}
}
}
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],
- to_list: &[TransformOperation],
- progress: f64) -> TransformList {
+fn add_weighted_transform_lists(from_list: &[TransformOperation],
+ to_list: &[TransformOperation],
+ self_portion: f64,
+ other_portion: f64) -> TransformList {
let mut result = vec![];
if can_interpolate_list(from_list, to_list) {
for (from, to) in from_list.iter().zip(to_list) {
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),
&TransformOperation::Rotate(tx, ty, tz, ta)) => {
let norm_f = ((fx * fx) + (fy * fy) + (fz * fz)).sqrt();
let norm_t = ((tx * tx) + (ty * ty) + (tz * tz)).sqrt();
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),
&TransformOperation::Perspective(_td)) => {
let mut fd_matrix = ComputedMatrix::identity();
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.
unreachable!();
}
}
}
} else {
@@ -1680,47 +1712,47 @@ pub struct MatrixDecomposed2D {
pub scale: Scale2D,
/// The rotation angle.
pub angle: f32,
/// The inner matrix.
pub matrix: InnerMatrix2D,
}
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;
let mut angle = self.angle;
let mut other_angle = other.angle;
if (scale.0 < 0.0 && other.scale.1 < 0.0) || (scale.1 < 0.0 && other.scale.0 < 0.0) {
scale.0 = -scale.0;
scale.1 = -scale.1;
@@ -1740,50 +1772,52 @@ impl Animatable for MatrixDecomposed2D {
angle -= 360.
}
else{
other_angle -= 360.
}
}
// 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,
scale: scale,
angle: angle,
matrix: matrix,
})
}
}
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))
}
}
}
impl From<ComputedMatrix> for MatrixDecomposed2D {
/// Decompose a 2D matrix.
/// https://drafts.csswg.org/css-transforms/#decomposing-a-2d-matrix
fn from(matrix: ComputedMatrix) -> MatrixDecomposed2D {
@@ -2089,93 +2123,99 @@ fn cross(row1: [f32; 3], row2: [f32; 3])
[
row1[1] * row2[2] - row1[2] * row2[1],
row1[2] * row2[0] - row1[0] * row2[2],
row1[0] * row2[1] - row1[1] * row2[0]
]
}
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");
+
+ let mut sum = *self;
- // 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));
+ // 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));
- // Interpolate quaternions using spherical linear interpolation (Slerp).
+ // 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 +
self.quaternion.3 * other.quaternion.3;
// Clamp product to -1.0 <= product <= 1.0
product = product.min(1.0);
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)
}
}
impl From<MatrixDecomposed3D> for ComputedMatrix {
/// Recompose a 3D matrix.
/// https://drafts.csswg.org/css-transforms/#recomposing-to-a-3d-matrix
fn from(decomposed: MatrixDecomposed3D) -> ComputedMatrix {
let mut matrix = ComputedMatrix::identity();
@@ -2369,58 +2409,58 @@ impl ComputedMatrix {
Some(x)
}
}
/// 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
TransformList(None)
}
};
Ok(result)
}
}
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)
}
}
}
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
match (self, other) {
(&Either::First(ref this), &Either::First(ref other)) => {
@@ -2492,31 +2532,36 @@ impl IntermediateRGBA {
pub fn new(red: f32, green: f32, blue: f32, alpha: f32) -> Self {
IntermediateRGBA { red: red, green: green, blue: blue, alpha: alpha }
}
}
/// 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))
}
}
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
self.compute_squared_distance(other).map(|sq| sq.sqrt())
@@ -2583,20 +2628,22 @@ impl<'a> From<<&'a Either<IntermediateCo
#[allow(missing_docs)]
pub enum IntermediateColor {
CurrentColor,
IntermediateRGBA(IntermediateRGBA),
}
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(()),
}
}
#[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {