servo: Merge #18134 - Introduce values::animated::Animate (from servo:we-are-leaving-babylon); r=emilio

Source-Repo: https://github.com/servo/servo
Source-Revision: 8ca9542de6838fc485e9e41013d84b396ff216a9

--HG--
extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear
extra : subtree_revision : 781cac1c82939307d62e6a53903845a7176f63dd
This commit is contained in:
Anthony Ramine 2017-08-22 07:22:10 -05:00
parent 1b3b415680
commit cc0adff3ff
23 changed files with 1160 additions and 1238 deletions

View File

@ -1410,15 +1410,15 @@ impl<'le> TElement for GeckoElement<'le> {
})
}
fn needs_transitions_update_per_property(&self,
property: &TransitionProperty,
combined_duration: f32,
before_change_style: &ComputedValues,
after_change_style: &ComputedValues,
existing_transitions: &HashMap<TransitionProperty,
Arc<AnimationValue>>)
-> bool {
use properties::animated_properties::Animatable;
fn needs_transitions_update_per_property(
&self,
property: &TransitionProperty,
combined_duration: f32,
before_change_style: &ComputedValues,
after_change_style: &ComputedValues,
existing_transitions: &HashMap<TransitionProperty, Arc<AnimationValue>>,
) -> bool {
use values::animated::{Animate, Procedure};
// |property| should be an animatable longhand
let animatable_longhand = AnimatableLonghand::from_transition_property(property).unwrap();
@ -1440,7 +1440,7 @@ impl<'le> TElement for GeckoElement<'le> {
combined_duration > 0.0f32 &&
from != to &&
from.interpolate(&to, 0.5).is_ok()
from.animate(&to, Procedure::Interpolate { progress: 0.5 }).is_ok()
}
#[inline]

View File

@ -87,10 +87,13 @@ macro_rules! define_keyword_type {
#[derive(Clone, ComputeSquaredDistance, Copy, PartialEq, ToCss)]
pub struct $name;
impl $crate::properties::animated_properties::Animatable for $name {
impl $crate::values::animated::Animate for $name {
#[inline]
fn add_weighted(&self, _other: &Self, _self_progress: f64, _other_progress: f64)
-> Result<Self, ()> {
fn animate(
&self,
_other: &Self,
_procedure: $crate::values::animated::Procedure,
) -> Result<Self, ()> {
Ok($name)
}
}

View File

@ -211,7 +211,7 @@ class Longhand(object):
self.animatable = False
self.transitionable = False
self.animation_type = None
# NB: Animatable implies clone because a property animation requires a
# NB: Animate implies clone because a property animation requires a
# copy of the computed value.
#
# See components/style/helpers/animated_properties.mako.rs.

View File

@ -133,17 +133,12 @@
);
% if need_animatable or animation_value_type == "ComputedValue":
use properties::animated_properties::Animatable;
use values::animated::ToAnimatedZero;
use values::animated::{Animate, Procedure, ToAnimatedZero};
impl Animatable for 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)
}
fn add(&self, other: &Self) -> Result<Self, ()> {
self.0.add(&other.0).map(T)
impl Animate for T {
#[inline]
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
Ok(T(self.0.animate(&other.0, procedure)?))
}
}

View File

@ -1115,9 +1115,8 @@ ${helpers.single_keyword_system("font-variant-caps",
}
pub mod computed_value {
use properties::animated_properties::Animatable;
use values::CSSFloat;
use values::animated::{ToAnimatedValue, ToAnimatedZero};
use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
use values::distance::{ComputeSquaredDistance, SquaredDistance};
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
@ -1137,12 +1136,12 @@ ${helpers.single_keyword_system("font-variant-caps",
}
}
impl Animatable for T {
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(number.add_weighted(other, self_portion, other_portion)?)),
impl Animate for T {
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
match (self, other) {
(&T::Number(ref number), &T::Number(ref other)) => {
Ok(T::Number(number.animate(other, procedure)?))
},
_ => Err(()),
}
}

View File

@ -26,8 +26,7 @@ ${helpers.single_keyword("caption-side", "top bottom",
use values::specified::length::NonNegativeLength;
pub mod computed_value {
use properties::animated_properties::Animatable;
use values::animated::{ToAnimatedValue, ToAnimatedZero};
use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
use values::computed::NonNegativeAu;
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
@ -38,15 +37,12 @@ ${helpers.single_keyword("caption-side", "top bottom",
}
/// https://drafts.csswg.org/css-transitions/#animtype-simple-list
impl Animatable for T {
impl Animate for T {
#[inline]
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64)
-> Result<Self, ()> {
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
Ok(T {
horizontal: self.horizontal.add_weighted(&other.horizontal,
self_portion, other_portion)?,
vertical: self.vertical.add_weighted(&other.vertical,
self_portion, other_portion)?,
horizontal: self.horizontal.animate(&other.horizontal, procedure)?,
vertical: self.vertical.animate(&other.vertical, procedure)?,
})
}
}

View File

@ -4,8 +4,7 @@
//! Animated types for CSS colors.
use properties::animated_properties::Animatable;
use values::animated::ToAnimatedZero;
use values::animated::{Animate, Procedure, ToAnimatedZero};
use values::distance::{ComputeSquaredDistance, SquaredDistance};
/// An animated RGBA color.
@ -39,13 +38,13 @@ impl RGBA {
}
}
/// Unlike Animatable for computed colors, we don't clamp any component values.
/// Unlike Animate for computed colors, we don't clamp any component values.
///
/// FIXME(nox): Why do computed colors even implement Animatable?
impl Animatable for RGBA {
/// FIXME(nox): Why do computed colors even implement Animate?
impl Animate for RGBA {
#[inline]
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
let mut alpha = self.alpha.add_weighted(&other.alpha, self_portion, other_portion)?;
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
let mut alpha = self.alpha.animate(&other.alpha, procedure)?;
if alpha <= 0. {
// Ideally we should return color value that only alpha component is
// 0, but this is what current gecko does.
@ -53,15 +52,9 @@ impl Animatable for RGBA {
}
alpha = alpha.min(1.);
let red = (self.red * self.alpha).add_weighted(
&(other.red * other.alpha), self_portion, other_portion
)? * 1. / alpha;
let green = (self.green * self.alpha).add_weighted(
&(other.green * other.alpha), self_portion, other_portion
)? * 1. / alpha;
let blue = (self.blue * self.alpha).add_weighted(
&(other.blue * other.alpha), self_portion, other_portion
)? * 1. / alpha;
let red = (self.red * self.alpha).animate(&(other.red * other.alpha), procedure)? * 1. / alpha;
let green = (self.green * self.alpha).animate(&(other.green * other.alpha), procedure)? * 1. / alpha;
let blue = (self.blue * self.alpha).animate(&(other.blue * other.alpha), procedure)? * 1. / alpha;
Ok(RGBA::new(red, green, blue, alpha))
}
@ -123,9 +116,9 @@ impl Color {
}
}
impl Animatable for Color {
impl Animate for Color {
#[inline]
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
// Common cases are interpolating between two numeric colors,
// two currentcolors, and a numeric color and a currentcolor.
//
@ -133,35 +126,35 @@ impl Animatable for Color {
// equals to one, so it may be broken for additive operation.
// To properly support additive color interpolation, we would
// need two ratio fields in computed color types.
let (this_weight, other_weight) = procedure.weights();
if self.foreground_ratio == other.foreground_ratio {
if self.is_currentcolor() {
Ok(Color::currentcolor())
} else {
Ok(Color {
color: self.color.add_weighted(&other.color, self_portion, other_portion)?,
color: self.color.animate(&other.color, procedure)?,
foreground_ratio: self.foreground_ratio,
})
}
} else if self.is_currentcolor() && other.is_numeric() {
Ok(Color {
color: other.color,
foreground_ratio: self_portion as f32,
foreground_ratio: this_weight as f32,
})
} else if self.is_numeric() && other.is_currentcolor() {
Ok(Color {
color: self.color,
foreground_ratio: other_portion as f32,
foreground_ratio: other_weight as f32,
})
} else {
// For interpolating between two complex colors, we need to
// generate colors with effective alpha value.
let self_color = self.effective_intermediate_rgba();
let other_color = other.effective_intermediate_rgba();
let color = self_color.add_weighted(&other_color, self_portion, other_portion)?;
let color = self_color.animate(&other_color, procedure)?;
// Then we compute the final foreground ratio, and derive
// the final alpha value from the effective alpha value.
let foreground_ratio = self.foreground_ratio
.add_weighted(&other.foreground_ratio, self_portion, other_portion)?;
let foreground_ratio = self.foreground_ratio.animate(&other.foreground_ratio, procedure)?;
let alpha = color.alpha / (1. - foreground_ratio);
Ok(Color {
color: RGBA {
@ -177,7 +170,7 @@ impl Animatable for Color {
impl ComputeSquaredDistance for Color {
#[inline]
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
// All comments in add_weighted also applies here.
// All comments from the Animate impl also applies here.
if self.foreground_ratio == other.foreground_ratio {
if self.is_currentcolor() {
Ok(SquaredDistance::Value(0.))

View File

@ -4,14 +4,13 @@
//! Animated types for CSS values related to effects.
use properties::animated_properties::Animatable;
use properties::longhands::box_shadow::computed_value::T as ComputedBoxShadowList;
use properties::longhands::filter::computed_value::T as ComputedFilterList;
use properties::longhands::text_shadow::computed_value::T as ComputedTextShadowList;
use std::cmp;
#[cfg(not(feature = "gecko"))]
use values::Impossible;
use values::animated::{ToAnimatedValue, ToAnimatedZero};
use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
use values::animated::color::RGBA;
use values::computed::{Angle, NonNegativeNumber};
use values::computed::length::{Length, NonNegativeLength};
@ -66,42 +65,36 @@ impl ToAnimatedValue for ComputedBoxShadowList {
}
}
impl<S> Animatable for ShadowList<S>
impl<S> Animate for ShadowList<S>
where
S: Animatable + Clone + ToAnimatedZero,
S: Animate + Clone + ToAnimatedZero,
{
#[inline]
fn add_weighted(
&self,
other: &Self,
self_portion: f64,
other_portion: f64,
) -> Result<Self, ()> {
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
if procedure == Procedure::Add {
return Ok(ShadowList(
self.0.iter().chain(&other.0).cloned().collect(),
));
}
// FIXME(nox): Use itertools here, to avoid the need for `unreachable!`.
let max_len = cmp::max(self.0.len(), other.0.len());
let mut shadows = Vec::with_capacity(max_len);
for i in 0..max_len {
shadows.push(match (self.0.get(i), other.0.get(i)) {
(Some(shadow), Some(other)) => {
shadow.add_weighted(other, self_portion, other_portion)?
shadow.animate(other, procedure)?
},
(Some(shadow), None) => {
shadow.add_weighted(&shadow.to_animated_zero()?, self_portion, other_portion)?
shadow.animate(&shadow.to_animated_zero()?, procedure)?
},
(None, Some(shadow)) => {
shadow.to_animated_zero()?.add_weighted(&shadow, self_portion, other_portion)?
shadow.to_animated_zero()?.animate(shadow, procedure)?
},
(None, None) => unreachable!(),
});
}
Ok(ShadowList(shadows))
}
#[inline]
fn add(&self, other: &Self) -> Result<Self, ()> {
Ok(ShadowList(
self.0.iter().cloned().chain(other.0.iter().cloned()).collect(),
))
}
}
impl<S> ComputeSquaredDistance for ShadowList<S>
@ -146,20 +139,15 @@ impl ToAnimatedValue for ComputedTextShadowList {
}
}
impl Animatable for BoxShadow {
impl Animate for BoxShadow {
#[inline]
fn add_weighted(
&self,
other: &Self,
self_portion: f64,
other_portion: f64,
) -> Result<Self, ()> {
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
if self.inset != other.inset {
return Err(());
}
Ok(BoxShadow {
base: self.base.add_weighted(&other.base, self_portion, other_portion)?,
spread: self.spread.add_weighted(&other.spread, self_portion, other_portion)?,
base: self.base.animate(&other.base, procedure)?,
spread: self.spread.animate(&other.spread, procedure)?,
inset: self.inset,
})
}
@ -224,19 +212,14 @@ impl ToAnimatedZero for FilterList {
}
}
impl Animatable for SimpleShadow {
impl Animate for SimpleShadow {
#[inline]
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
let color = self.color.add_weighted(&other.color, self_portion, other_portion)?;
let horizontal = self.horizontal.add_weighted(&other.horizontal, self_portion, other_portion)?;
let vertical = self.vertical.add_weighted(&other.vertical, self_portion, other_portion)?;
let blur = self.blur.add_weighted(&other.blur, self_portion, other_portion)?;
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
Ok(SimpleShadow {
color: color,
horizontal: horizontal,
vertical: vertical,
blur: blur,
color: self.color.animate(&other.color, procedure)?,
horizontal: self.horizontal.animate(&other.horizontal, procedure)?,
vertical: self.vertical.animate(&other.vertical, procedure)?,
blur: self.blur.animate(&other.blur, procedure)?,
})
}
}
@ -245,7 +228,7 @@ impl ToAnimatedZero for SimpleShadow {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
Ok(SimpleShadow {
color: Some(RGBA::transparent()),
color: self.color.to_animated_zero()?,
horizontal: self.horizontal.to_animated_zero()?,
vertical: self.vertical.to_animated_zero()?,
blur: self.blur.to_animated_zero()?,

View File

@ -9,6 +9,7 @@
//! module's raison d'être is to ultimately contain all these types.
use app_units::Au;
use euclid::{Point2D, Size2D};
use smallvec::SmallVec;
use std::cmp::max;
use values::computed::Angle as ComputedAngle;
@ -27,6 +28,26 @@ use values::specified::url::SpecifiedUrl;
pub mod color;
pub mod effects;
/// Animating from one value to another.
pub trait Animate: Sized {
/// Animate a value towards another one, given an animation procedure.
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()>;
}
/// An animation procedure.
///
/// https://w3c.github.io/web-animations/#procedures-for-animating-properties
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Procedure {
/// https://w3c.github.io/web-animations/#animation-interpolation
Interpolate { progress: f64 },
/// https://w3c.github.io/web-animations/#animation-addition
Add,
/// https://w3c.github.io/web-animations/#animation-accumulation
Accumulate { count: u64 },
}
/// Conversion between computed values and intermediate values for animations.
///
/// Notably, colors are represented as four floats during animations.
@ -41,6 +62,108 @@ pub trait ToAnimatedValue {
fn from_animated_value(animated: Self::AnimatedValue) -> Self;
}
/// Marker trait for computed values with the same representation during animations.
pub trait AnimatedValueAsComputed {}
/// Returns a value similar to `self` that represents zero.
pub trait ToAnimatedZero: Sized {
/// 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.
fn to_animated_zero(&self) -> Result<Self, ()>;
}
impl Procedure {
/// Returns this procedure as a pair of weights.
///
/// This is useful for animations that don't animate differently
/// depending on the used procedure.
#[inline]
pub fn weights(self) -> (f64, f64) {
match self {
Procedure::Interpolate { progress } => (1. - progress, progress),
Procedure::Add => (1., 1.),
Procedure::Accumulate { count } => (count as f64, 1.),
}
}
}
/// https://drafts.csswg.org/css-transitions/#animtype-number
impl Animate for i32 {
#[inline]
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
Ok(((*self as f64).animate(&(*other as f64), procedure)? + 0.5).floor() as i32)
}
}
/// https://drafts.csswg.org/css-transitions/#animtype-number
impl Animate for f32 {
#[inline]
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
Ok((*self as f64).animate(&(*other as f64), procedure)? as f32)
}
}
/// https://drafts.csswg.org/css-transitions/#animtype-number
impl Animate for f64 {
#[inline]
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
let (self_weight, other_weight) = procedure.weights();
Ok(*self * self_weight + *other * other_weight)
}
}
impl<T> Animate for Option<T>
where
T: Animate,
{
#[inline]
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
match (self.as_ref(), other.as_ref()) {
(Some(ref this), Some(ref other)) => Ok(Some(this.animate(other, procedure)?)),
(None, None) => Ok(None),
_ => Err(()),
}
}
}
impl Animate for Au {
#[inline]
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
Ok(Au(self.0.animate(&other.0, procedure)?))
}
}
impl<T> Animate for Size2D<T>
where
T: Animate + Copy,
{
#[inline]
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
Ok(Size2D::new(
self.width.animate(&other.width, procedure)?,
self.height.animate(&other.height, procedure)?,
))
}
}
impl<T> Animate for Point2D<T>
where
T: Animate + Copy,
{
#[inline]
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
Ok(Point2D::new(
self.x.animate(&other.x, procedure)?,
self.y.animate(&other.y, procedure)?,
))
}
}
impl<T> ToAnimatedValue for Option<T>
where
T: ToAnimatedValue,
@ -92,9 +215,6 @@ where
}
}
/// Marker trait for computed values with the same representation during animations.
pub trait AnimatedValueAsComputed {}
impl AnimatedValueAsComputed for Au {}
impl AnimatedValueAsComputed for ComputedAngle {}
impl AnimatedValueAsComputed for SpecifiedUrl {}
@ -263,18 +383,6 @@ impl ToAnimatedValue for ComputedMozLength {
}
}
/// Returns a value similar to `self` that represents zero.
pub trait ToAnimatedZero: Sized {
/// 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.
fn to_animated_zero(&self) -> Result<Self, ()>;
}
impl ToAnimatedZero for Au {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> { Ok(Au(0)) }
@ -294,3 +402,16 @@ impl ToAnimatedZero for i32 {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> { Ok(0) }
}
impl<T> ToAnimatedZero for Option<T>
where
T: ToAnimatedZero,
{
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
match *self {
Some(ref value) => Ok(Some(value.to_animated_zero()?)),
None => Ok(None),
}
}
}

View File

@ -4,11 +4,11 @@
//! Computed angles.
use properties::animated_properties::Animatable;
use std::{f32, f64, fmt};
use std::f64::consts::PI;
use style_traits::ToCss;
use values::CSSFloat;
use values::animated::{Animate, Procedure, ToAnimatedZero};
use values::distance::{ComputeSquaredDistance, SquaredDistance};
/// A computed angle.
@ -65,24 +65,34 @@ impl Angle {
}
/// https://drafts.csswg.org/css-transitions/#animtype-number
impl Animatable for Angle {
impl Animate for Angle {
#[inline]
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
match (self, other) {
(&Angle::Degree(ref this), &Angle::Degree(ref other)) => {
Ok(Angle::Degree(this.add_weighted(other, self_portion, other_portion)?))
Ok(Angle::Degree(this.animate(other, procedure)?))
},
(&Angle::Gradian(ref this), &Angle::Gradian(ref other)) => {
Ok(Angle::Gradian(this.add_weighted(other, self_portion, other_portion)?))
Ok(Angle::Gradian(this.animate(other, procedure)?))
},
(&Angle::Turn(ref this), &Angle::Turn(ref other)) => {
Ok(Angle::Turn(this.add_weighted(other, self_portion, other_portion)?))
Ok(Angle::Turn(this.animate(other, procedure)?))
},
_ => {
self.radians()
.add_weighted(&other.radians(), self_portion, other_portion)
.map(Angle::from_radians)
}
Ok(Angle::from_radians(self.radians().animate(&other.radians(), procedure)?))
},
}
}
}
impl ToAnimatedZero for Angle {
#[inline]
fn to_animated_zero(&self) -> Result<Angle, ()> {
match *self {
Angle::Degree(ref this) => Ok(Angle::Degree(this.to_animated_zero()?)),
Angle::Gradian(ref this) => Ok(Angle::Gradian(this.to_animated_zero()?)),
Angle::Radian(ref this) => Ok(Angle::Radian(this.to_animated_zero()?)),
Angle::Turn(ref this) => Ok(Angle::Turn(this.to_animated_zero()?)),
}
}
}

View File

@ -4,9 +4,9 @@
//! Computed types for CSS values related to backgrounds.
use properties::animated_properties::{Animatable, RepeatableListAnimatable};
use properties::animated_properties::RepeatableListAnimatable;
use properties::longhands::background_size::computed_value::T as BackgroundSizeList;
use values::animated::{ToAnimatedValue, ToAnimatedZero};
use values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
use values::computed::length::LengthOrPercentageOrAuto;
use values::generics::background::BackgroundSize as GenericBackgroundSize;
@ -15,16 +15,16 @@ pub type BackgroundSize = GenericBackgroundSize<LengthOrPercentageOrAuto>;
impl RepeatableListAnimatable for BackgroundSize {}
impl Animatable for BackgroundSize {
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
impl Animate for BackgroundSize {
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
match (self, other) {
(
&GenericBackgroundSize::Explicit { width: self_width, height: self_height },
&GenericBackgroundSize::Explicit { width: other_width, height: other_height },
) => {
Ok(GenericBackgroundSize::Explicit {
width: self_width.add_weighted(&other_width, self_portion, other_portion)?,
height: self_height.add_weighted(&other_height, self_portion, other_portion)?,
width: self_width.animate(&other_width, procedure)?,
height: self_height.animate(&other_height, procedure)?,
})
}
_ => Err(()),

View File

@ -11,6 +11,7 @@ use style_traits::ToCss;
use style_traits::values::specified::AllowedLengthType;
use super::{Number, ToComputedValue, Context, Percentage};
use values::{Auto, CSSFloat, Either, ExtremumLength, None_, Normal, specified};
use values::animated::ToAnimatedZero;
use values::computed::{NonNegativeAu, NonNegativeNumber};
use values::distance::{ComputeSquaredDistance, SquaredDistance};
use values::generics::NonNegative;
@ -72,6 +73,17 @@ pub struct CalcLengthOrPercentage {
pub percentage: Option<Percentage>,
}
impl ToAnimatedZero for CalcLengthOrPercentage {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
Ok(CalcLengthOrPercentage {
clamping_mode: self.clamping_mode,
length: self.length.to_animated_zero()?,
percentage: self.percentage.to_animated_zero()?,
})
}
}
impl ComputeSquaredDistance for CalcLengthOrPercentage {
#[inline]
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {

View File

@ -4,11 +4,10 @@
//! Computed percentages.
use properties::animated_properties::Animatable;
use std::fmt;
use style_traits::ToCss;
use values::{CSSFloat, serialize_percentage};
use values::animated::ToAnimatedZero;
use values::animated::{Animate, Procedure, ToAnimatedZero};
/// A computed percentage.
#[derive(Clone, ComputeSquaredDistance, Copy, Debug, Default, HasViewportPercentage, PartialEq, PartialOrd)]
@ -36,10 +35,10 @@ impl Percentage {
}
/// https://drafts.csswg.org/css-transitions/#animtype-percentage
impl Animatable for Percentage {
impl Animate for Percentage {
#[inline]
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
Ok(Percentage((self.0 as f64 * self_portion + other.0 as f64 * other_portion) as f32))
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
Ok(Percentage(self.0.animate(&other.0, procedure)?))
}
}

View File

@ -4,9 +4,8 @@
//! Computed types for text properties.
use properties::animated_properties::Animatable;
use values::{CSSInteger, CSSFloat};
use values::animated::ToAnimatedZero;
use values::animated::{Animate, Procedure, ToAnimatedZero};
use values::computed::{NonNegativeAu, NonNegativeNumber};
use values::computed::length::{Length, LengthOrPercentage};
use values::generics::text::InitialLetter as GenericInitialLetter;
@ -25,21 +24,21 @@ pub type WordSpacing = Spacing<LengthOrPercentage>;
/// A computed value for the `line-height` property.
pub type LineHeight = GenericLineHeight<NonNegativeNumber, NonNegativeAu>;
impl Animatable for LineHeight {
impl Animate for LineHeight {
#[inline]
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
match (*self, *other) {
(GenericLineHeight::Length(ref this), GenericLineHeight::Length(ref other)) => {
this.add_weighted(other, self_portion, other_portion).map(GenericLineHeight::Length)
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
match (self, other) {
(&GenericLineHeight::Length(ref this), &GenericLineHeight::Length(ref other)) => {
Ok(GenericLineHeight::Length(this.animate(other, procedure)?))
},
(GenericLineHeight::Number(ref this), GenericLineHeight::Number(ref other)) => {
this.add_weighted(other, self_portion, other_portion).map(GenericLineHeight::Number)
(&GenericLineHeight::Number(ref this), &GenericLineHeight::Number(ref other)) => {
Ok(GenericLineHeight::Number(this.animate(other, procedure)?))
},
(GenericLineHeight::Normal, GenericLineHeight::Normal) => {
(&GenericLineHeight::Normal, &GenericLineHeight::Normal) => {
Ok(GenericLineHeight::Normal)
},
#[cfg(feature = "gecko")]
(GenericLineHeight::MozBlockHeight, GenericLineHeight::MozBlockHeight) => {
(&GenericLineHeight::MozBlockHeight, &GenericLineHeight::MozBlockHeight) => {
Ok(GenericLineHeight::MozBlockHeight)
},
_ => Err(()),

View File

@ -4,8 +4,7 @@
//! Computed types for CSS values that are related to transformations.
use properties::animated_properties::Animatable;
use values::animated::ToAnimatedZero;
use values::animated::{Animate, Procedure, ToAnimatedZero};
use values::computed::{Length, LengthOrPercentage, Number, Percentage};
use values::generics::transform::TimingFunction as GenericTimingFunction;
use values::generics::transform::TransformOrigin as GenericTransformOrigin;
@ -28,13 +27,13 @@ impl TransformOrigin {
}
}
impl Animatable for TransformOrigin {
impl Animate for TransformOrigin {
#[inline]
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
Ok(Self::new(
self.horizontal.add_weighted(&other.horizontal, self_portion, other_portion)?,
self.vertical.add_weighted(&other.vertical, self_portion, other_portion)?,
self.depth.add_weighted(&other.depth, self_portion, other_portion)?,
self.horizontal.animate(&other.horizontal, procedure)?,
self.vertical.animate(&other.vertical, procedure)?,
self.depth.animate(&other.depth, procedure)?,
))
}
}

View File

@ -5,10 +5,9 @@
//! CSS handling for the [`basic-shape`](https://drafts.csswg.org/css-shapes/#typedef-basic-shape)
//! types that are generic over their `ToCss` implementations.
use properties::animated_properties::Animatable;
use std::fmt;
use style_traits::{HasViewportPercentage, ToCss};
use values::animated::ToAnimatedZero;
use values::animated::{Animate, Procedure, ToAnimatedZero};
use values::computed::ComputedValueAsSpecified;
use values::distance::{ComputeSquaredDistance, SquaredDistance};
use values::generics::border::BorderRadius;
@ -123,24 +122,21 @@ define_css_keyword_enum!(FillRule:
);
add_impls_for_keyword_enum!(FillRule);
impl<B, T, U> Animatable for ShapeSource<B, T, U>
impl<B, T, U> Animate for ShapeSource<B, T, U>
where
B: Animatable,
B: Animate,
T: Clone + PartialEq,
{
fn add_weighted(
&self,
other: &Self,
self_portion: f64,
other_portion: f64,
) -> Result<Self, ()> {
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
match (self, other) {
(
&ShapeSource::Shape(ref this, ref this_box),
&ShapeSource::Shape(ref other, ref other_box),
) if this_box == other_box => {
let shape = this.add_weighted(other, self_portion, other_portion)?;
Ok(ShapeSource::Shape(shape, this_box.clone()))
Ok(ShapeSource::Shape(
this.animate(other, procedure)?,
this_box.clone(),
))
},
_ => Err(()),
}
@ -178,49 +174,40 @@ impl<B, T, U> HasViewportPercentage for ShapeSource<B, T, U> {
fn has_viewport_percentage(&self) -> bool { false }
}
impl<H, V, L> Animatable for BasicShape<H, V, L>
impl<H, V, L> Animate for BasicShape<H, V, L>
where
H: Animatable,
V: Animatable,
L: Animatable + Copy,
H: Animate,
V: Animate,
L: Animate + Copy,
{
fn add_weighted(
&self,
other: &Self,
self_portion: f64,
other_portion: f64,
) -> Result<Self, ()> {
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
match (self, other) {
(&BasicShape::Circle(ref this), &BasicShape::Circle(ref other)) => {
Ok(BasicShape::Circle(this.add_weighted(other, self_portion, other_portion)?))
Ok(BasicShape::Circle(this.animate(other, procedure)?))
},
(&BasicShape::Ellipse(ref this), &BasicShape::Ellipse(ref other)) => {
Ok(BasicShape::Ellipse(this.add_weighted(other, self_portion, other_portion)?))
Ok(BasicShape::Ellipse(this.animate(other, procedure)?))
},
(&BasicShape::Inset(ref this), &BasicShape::Inset(ref other)) => {
Ok(BasicShape::Inset(this.add_weighted(other, self_portion, other_portion)?))
Ok(BasicShape::Inset(this.animate(other, procedure)?))
},
(&BasicShape::Polygon(ref this), &BasicShape::Polygon(ref other)) => {
Ok(BasicShape::Polygon(this.add_weighted(other, self_portion, other_portion)?))
Ok(BasicShape::Polygon(this.animate(other, procedure)?))
},
_ => Err(()),
}
}
}
impl<L> Animatable for InsetRect<L>
impl<L> Animate for InsetRect<L>
where
L: Animatable + Copy,
L: Animate + Copy,
{
fn add_weighted(
&self,
other: &Self,
self_portion: f64,
other_portion: f64,
) -> Result<Self, ()> {
let rect = self.rect.add_weighted(&other.rect, self_portion, other_portion)?;
let round = self.round.add_weighted(&other.round, self_portion, other_portion)?;
Ok(InsetRect { rect, round })
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
Ok(InsetRect {
rect: self.rect.animate(&other.rect, procedure)?,
round: self.round.animate(&other.round, procedure)?,
})
}
}
@ -238,56 +225,43 @@ impl<L> ToCss for InsetRect<L>
}
}
impl<H, V, L> Animatable for Circle<H, V, L>
impl<H, V, L> Animate for Circle<H, V, L>
where
H: Animatable,
V: Animatable,
L: Animatable,
H: Animate,
V: Animate,
L: Animate,
{
fn add_weighted(
&self,
other: &Self,
self_portion: f64,
other_portion: f64,
) -> Result<Self, ()> {
let position = self.position.add_weighted(&other.position, self_portion, other_portion)?;
let radius = self.radius.add_weighted(&other.radius, self_portion, other_portion)?;
Ok(Circle { position, radius })
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
Ok(Circle {
position: self.position.animate(&other.position, procedure)?,
radius: self.radius.animate(&other.radius, procedure)?,
})
}
}
impl<H, V, L> Animatable for Ellipse<H, V, L>
impl<H, V, L> Animate for Ellipse<H, V, L>
where
H: Animatable,
V: Animatable,
L: Animatable,
H: Animate,
V: Animate,
L: Animate,
{
fn add_weighted(
&self,
other: &Self,
self_portion: f64,
other_portion: f64,
) -> Result<Self, ()> {
let position = self.position.add_weighted(&other.position, self_portion, other_portion)?;
let semiaxis_x = self.semiaxis_x.add_weighted(&other.semiaxis_x, self_portion, other_portion)?;
let semiaxis_y = self.semiaxis_y.add_weighted(&other.semiaxis_y, self_portion, other_portion)?;
Ok(Ellipse { position, semiaxis_x, semiaxis_y })
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
Ok(Ellipse {
position: self.position.animate(&other.position, procedure)?,
semiaxis_x: self.semiaxis_x.animate(&other.semiaxis_x, procedure)?,
semiaxis_y: self.semiaxis_y.animate(&other.semiaxis_y, procedure)?,
})
}
}
impl<L> Animatable for ShapeRadius<L>
impl<L> Animate for ShapeRadius<L>
where
L: Animatable,
L: Animate,
{
fn add_weighted(
&self,
other: &Self,
self_portion: f64,
other_portion: f64,
) -> Result<Self, ()> {
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
match (self, other) {
(&ShapeRadius::Length(ref this), &ShapeRadius::Length(ref other)) => {
Ok(ShapeRadius::Length(this.add_weighted(other, self_portion, other_portion)?))
Ok(ShapeRadius::Length(this.animate(other, procedure)?))
},
_ => Err(()),
}
@ -299,16 +273,11 @@ impl<L> Default for ShapeRadius<L> {
fn default() -> Self { ShapeRadius::ClosestSide }
}
impl<L> Animatable for Polygon<L>
impl<L> Animate for Polygon<L>
where
L: Animatable,
L: Animate,
{
fn add_weighted(
&self,
other: &Self,
self_portion: f64,
other_portion: f64,
) -> Result<Self, ()> {
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
if self.fill != other.fill {
return Err(());
}
@ -316,9 +285,10 @@ where
return Err(());
}
let coordinates = self.coordinates.iter().zip(other.coordinates.iter()).map(|(this, other)| {
let x = this.0.add_weighted(&other.0, self_portion, other_portion)?;
let y = this.1.add_weighted(&other.1, self_portion, other_portion)?;
Ok((x, y))
Ok((
this.0.animate(&other.0, procedure)?,
this.1.animate(&other.1, procedure)?,
))
}).collect::<Result<Vec<_>, _>>()?;
Ok(Polygon { fill: self.fill, coordinates })
}

View File

@ -5,9 +5,9 @@
//! Generic types for CSS values related to borders.
use euclid::Size2D;
use properties::animated_properties::Animatable;
use std::fmt;
use style_traits::ToCss;
use values::animated::{Animate, Procedure};
use values::generics::rect::Rect;
/// A generic value for a single side of a `border-image-width` property.
@ -113,21 +113,17 @@ impl<L> BorderRadius<L>
}
}
impl<L> Animatable for BorderRadius<L>
impl<L> Animate for BorderRadius<L>
where
L: Animatable + Copy,
L: Animate + Copy,
{
fn add_weighted(
&self,
other: &Self,
self_portion: f64,
other_portion: f64,
) -> Result<Self, ()> {
let tl = self.top_left.add_weighted(&other.top_left, self_portion, other_portion)?;
let tr = self.top_right.add_weighted(&other.top_right, self_portion, other_portion)?;
let br = self.bottom_right.add_weighted(&other.bottom_right, self_portion, other_portion)?;
let bl = self.bottom_left.add_weighted(&other.bottom_left, self_portion, other_portion)?;
Ok(BorderRadius::new(tl, tr, br, bl))
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
Ok(BorderRadius::new(
self.top_left.animate(&other.top_left, procedure)?,
self.top_right.animate(&other.top_right, procedure)?,
self.bottom_right.animate(&other.bottom_right, procedure)?,
self.bottom_left.animate(&other.bottom_left, procedure)?,
))
}
}
@ -163,18 +159,13 @@ impl<L: Clone> From<L> for BorderCornerRadius<L> {
}
}
impl<L> Animatable for BorderCornerRadius<L>
impl<L> Animate for BorderCornerRadius<L>
where
L: Animatable + Copy,
L: Animate + Copy,
{
#[inline]
fn add_weighted(
&self,
other: &Self,
self_portion: f64,
other_portion: f64,
) -> Result<Self, ()> {
Ok(BorderCornerRadius(self.0.add_weighted(&other.0, self_portion, other_portion)?))
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
Ok(BorderCornerRadius(self.0.animate(&other.0, procedure)?))
}
}

View File

@ -6,9 +6,9 @@
use cssparser::Parser;
use parser::{Parse, ParserContext};
use properties::animated_properties::Animatable;
use std::fmt;
use style_traits::{ToCss, ParseError};
use values::animated::{Animate, Procedure};
/// A CSS value made of four components, where its `ToCss` impl will try to
/// serialize as few components as possible, like for example in `border-width`.
@ -52,21 +52,17 @@ impl<T> Rect<T>
}
}
impl<L> Animatable for Rect<L>
impl<L> Animate for Rect<L>
where
L: Animatable,
L: Animate,
{
fn add_weighted(
&self,
other: &Self,
self_portion: f64,
other_portion: f64,
) -> Result<Self, ()> {
let first = self.0.add_weighted(&other.0, self_portion, other_portion)?;
let second = self.1.add_weighted(&other.1, self_portion, other_portion)?;
let third = self.2.add_weighted(&other.2, self_portion, other_portion)?;
let fourth = self.3.add_weighted(&other.3, self_portion, other_portion)?;
Ok(Rect(first, second, third, fourth))
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
Ok(Rect(
self.0.animate(&other.0, procedure)?,
self.1.animate(&other.1, procedure)?,
self.2.animate(&other.2, procedure)?,
self.3.animate(&other.3, procedure)?,
))
}
}

View File

@ -7,9 +7,8 @@
use app_units::Au;
use cssparser::Parser;
use parser::ParserContext;
use properties::animated_properties::Animatable;
use style_traits::ParseError;
use values::animated::ToAnimatedZero;
use values::animated::{Animate, Procedure, ToAnimatedZero};
use values::distance::{ComputeSquaredDistance, SquaredDistance};
/// A generic value for the `initial-letter` property.
@ -72,18 +71,19 @@ impl<Value> Spacing<Value> {
}
}
impl<Value> Animatable for Spacing<Value>
where Value: Animatable + From<Au>,
impl<Value> Animate for Spacing<Value>
where
Value: Animate + From<Au>,
{
#[inline]
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> {
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
if let (&Spacing::Normal, &Spacing::Normal) = (self, other) {
return Ok(Spacing::Normal);
}
let zero = Value::from(Au(0));
let this = self.value().unwrap_or(&zero);
let other = other.value().unwrap_or(&zero);
this.add_weighted(other, self_portion, other_portion).map(Spacing::Value)
Ok(Spacing::Value(this.animate(other, procedure)?))
}
}

View File

@ -105,7 +105,7 @@ use style::properties::{IS_FIELDSET_CONTENT, IS_LINK, IS_VISITED_LINK, LonghandI
use style::properties::{PropertyDeclaration, PropertyDeclarationBlock, PropertyId, ShorthandId};
use style::properties::{SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP, SourcePropertyDeclaration, StyleBuilder};
use style::properties::PROHIBIT_DISPLAY_CONTENTS;
use style::properties::animated_properties::{Animatable, AnimatableLonghand, AnimationValue};
use style::properties::animated_properties::{AnimatableLonghand, AnimationValue};
use style::properties::animated_properties::compare_property_priority;
use style::properties::parse_one_declaration_into;
use style::rule_tree::StyleSource;
@ -128,7 +128,7 @@ use style::traversal::{DomTraversal, TraversalDriver};
use style::traversal::resolve_style;
use style::traversal_flags::{TraversalFlags, self};
use style::values::{CustomIdent, KeyframesName};
use style::values::animated::ToAnimatedZero;
use style::values::animated::{Animate, Procedure, ToAnimatedZero};
use style::values::computed::Context;
use style::values::distance::ComputeSquaredDistance;
use style_traits::{PARSING_MODE_DEFAULT, ToCss};
@ -319,7 +319,7 @@ pub extern "C" fn Servo_AnimationValues_Interpolate(from: RawServoAnimationValue
{
let from_value = AnimationValue::as_arc(&from);
let to_value = AnimationValue::as_arc(&to);
if let Ok(value) = from_value.interpolate(to_value, progress) {
if let Ok(value) = from_value.animate(to_value, Procedure::Interpolate { progress }) {
Arc::new(value).into_strong()
} else {
RawServoAnimationValueStrong::null()
@ -332,7 +332,7 @@ pub extern "C" fn Servo_AnimationValues_IsInterpolable(from: RawServoAnimationVa
-> bool {
let from_value = AnimationValue::as_arc(&from);
let to_value = AnimationValue::as_arc(&to);
from_value.interpolate(to_value, 0.5).is_ok()
from_value.animate(to_value, Procedure::Interpolate { progress: 0.5 }).is_ok()
}
#[no_mangle]
@ -342,7 +342,7 @@ pub extern "C" fn Servo_AnimationValues_Add(a: RawServoAnimationValueBorrowed,
{
let a_value = AnimationValue::as_arc(&a);
let b_value = AnimationValue::as_arc(&b);
if let Ok(value) = a_value.add(b_value) {
if let Ok(value) = a_value.animate(b_value, Procedure::Add) {
Arc::new(value).into_strong()
} else {
RawServoAnimationValueStrong::null()
@ -357,7 +357,7 @@ pub extern "C" fn Servo_AnimationValues_Accumulate(a: RawServoAnimationValueBorr
{
let a_value = AnimationValue::as_arc(&a);
let b_value = AnimationValue::as_arc(&b);
if let Ok(value) = a_value.accumulate(b_value, count) {
if let Ok(value) = a_value.animate(b_value, Procedure::Accumulate { count }) {
Arc::new(value).into_strong()
} else {
RawServoAnimationValueStrong::null()
@ -463,12 +463,16 @@ pub extern "C" fn Servo_AnimationCompose(raw_value_map: RawServoAnimationValueMa
CompositeOperation::Add => {
debug_assert!(need_underlying_value,
"Should have detected we need an underlying value");
underlying_value.as_ref().unwrap().add(keyframe_value).ok()
underlying_value.as_ref().unwrap().animate(keyframe_value, Procedure::Add).ok()
},
CompositeOperation::Accumulate => {
debug_assert!(need_underlying_value,
"Should have detected we need an underlying value");
underlying_value.as_ref().unwrap().accumulate(keyframe_value, 1).ok()
underlying_value
.as_ref()
.unwrap()
.animate(keyframe_value, Procedure::Accumulate { count: 1 })
.ok()
},
_ => None,
}
@ -507,11 +511,17 @@ pub extern "C" fn Servo_AnimationCompose(raw_value_map: RawServoAnimationValueMa
-> Option<AnimationValue> {
let count = computed_timing.mCurrentIteration;
match composited_value {
Some(endpoint) => last_value.accumulate(&endpoint, count)
.ok()
.or(Some(endpoint)),
None => last_value.accumulate(keyframe_value.unwrap(), count)
.ok(),
Some(endpoint) => {
last_value
.animate(&endpoint, Procedure::Accumulate { count })
.ok()
.or(Some(endpoint))
},
None => {
last_value
.animate(keyframe_value.unwrap(), Procedure::Accumulate { count })
.ok()
},
}
};
@ -535,12 +545,12 @@ pub extern "C" fn Servo_AnimationCompose(raw_value_map: RawServoAnimationValueMa
return;
}
let position = unsafe {
let pos = unsafe {
Gecko_GetPositionInSegment(segment, progress, computed_timing.mBeforeFlag)
};
if let Ok(value) = from_value.interpolate(to_value, position) {
if let Ok(value) = from_value.animate(to_value, Procedure::Interpolate { progress: pos }) {
value_map.insert(property, value);
} else if position < 0.5 {
} else if pos < 0.5 {
value_map.insert(property, from_value.clone());
} else {
value_map.insert(property, to_value.clone());
@ -2080,8 +2090,8 @@ pub extern "C" fn Servo_MatrixTransform_Operate(matrix_operator: MatrixTransform
let from = ComputedMatrix::from(unsafe { from.as_ref() }.expect("not a valid 'from' matrix"));
let to = ComputedMatrix::from(unsafe { to.as_ref() }.expect("not a valid 'to' matrix"));
let result = match matrix_operator {
Interpolate => from.interpolate(&to, progress),
Accumulate => from.accumulate(&to, progress as u64),
Interpolate => from.animate(&to, Procedure::Interpolate { progress }),
Accumulate => from.animate(&to, Procedure::Accumulate { count: progress as u64 }),
};
let output = unsafe { output.as_mut() }.expect("not a valid 'output' matrix");

View File

@ -4,16 +4,17 @@
use app_units::Au;
use cssparser::RGBA;
use style::properties::animated_properties::Animatable;
use style::properties::longhands::transform::computed_value::ComputedOperation as TransformOperation;
use style::properties::longhands::transform::computed_value::T as TransformList;
use style::values::animated::ToAnimatedValue;
use style::values::animated::{Animate, Procedure, ToAnimatedValue};
use style::values::computed::Percentage;
fn interpolate_rgba(from: RGBA, to: RGBA, progress: f64) -> RGBA {
let from = from.to_animated_value();
let to = to.to_animated_value();
RGBA::from_animated_value(from.interpolate(&to, progress).unwrap())
RGBA::from_animated_value(
from.animate(&to, Procedure::Interpolate { progress }).unwrap(),
)
}
// Color
@ -74,11 +75,14 @@ fn test_transform_interpolation_on_translate() {
TransformOperation::Translate(LengthOrPercentage::Length(Au(100)),
LengthOrPercentage::Length(Au(0)),
Au(75))]));
assert_eq!(from.interpolate(&to, 0.5).unwrap(),
TransformList(Some(vec![
TransformOperation::Translate(LengthOrPercentage::Length(Au(50)),
LengthOrPercentage::Length(Au(50)),
Au(50))])));
assert_eq!(
from.animate(&to, Procedure::Interpolate { progress: 0.5 }).unwrap(),
TransformList(Some(vec![TransformOperation::Translate(
LengthOrPercentage::Length(Au(50)),
LengthOrPercentage::Length(Au(50)),
Au(50),
)]))
);
let from = TransformList(Some(vec![TransformOperation::Translate(
LengthOrPercentage::Percentage(Percentage(0.5)),
@ -90,7 +94,7 @@ fn test_transform_interpolation_on_translate() {
LengthOrPercentage::Length(Au(50)),
Au(75))]));
assert_eq!(
from.interpolate(&to, 0.5).unwrap(),
from.animate(&to, Procedure::Interpolate { progress: 0.5 }).unwrap(),
TransformList(Some(vec![TransformOperation::Translate(
// calc(50px + 25%)
LengthOrPercentage::Calc(CalcLengthOrPercentage::new(Au(50), Some(Percentage(0.25)))),
@ -105,8 +109,10 @@ fn test_transform_interpolation_on_translate() {
fn test_transform_interpolation_on_scale() {
let from = TransformList(Some(vec![TransformOperation::Scale(1.0, 2.0, 1.0)]));
let to = TransformList(Some(vec![TransformOperation::Scale(2.0, 4.0, 2.0)]));
assert_eq!(from.interpolate(&to, 0.5).unwrap(),
TransformList(Some(vec![TransformOperation::Scale(1.5, 3.0, 1.5)])));
assert_eq!(
from.animate(&to, Procedure::Interpolate { progress: 0.5 }).unwrap(),
TransformList(Some(vec![TransformOperation::Scale(1.5, 3.0, 1.5)]))
);
}
#[test]
@ -117,9 +123,12 @@ fn test_transform_interpolation_on_rotate() {
Angle::from_radians(0.0))]));
let to = TransformList(Some(vec![TransformOperation::Rotate(0.0, 0.0, 1.0,
Angle::from_radians(100.0))]));
assert_eq!(from.interpolate(&to, 0.5).unwrap(),
TransformList(Some(vec![TransformOperation::Rotate(0.0, 0.0, 1.0,
Angle::from_radians(50.0))])));
assert_eq!(
from.animate(&to, Procedure::Interpolate { progress: 0.5 }).unwrap(),
TransformList(Some(vec![
TransformOperation::Rotate(0.0, 0.0, 1.0, Angle::from_radians(50.0)),
]))
);
}
#[test]
@ -130,9 +139,13 @@ fn test_transform_interpolation_on_skew() {
Angle::from_radians(100.0))]));
let to = TransformList(Some(vec![TransformOperation::Skew(Angle::from_radians(100.0),
Angle::from_radians(0.0))]));
assert_eq!(from.interpolate(&to, 0.5).unwrap(),
TransformList(Some(vec![TransformOperation::Skew(Angle::from_radians(50.0),
Angle::from_radians(50.0))])));
assert_eq!(
from.animate(&to, Procedure::Interpolate { progress: 0.5 }).unwrap(),
TransformList(Some(vec![TransformOperation::Skew(
Angle::from_radians(50.0),
Angle::from_radians(50.0),
)]))
);
}
#[test]
@ -146,7 +159,7 @@ fn test_transform_interpolation_on_mismatched_lists() {
LengthOrPercentage::Length(Au(0)),
Au(0))]));
assert_eq!(
from.interpolate(&to, 0.5).unwrap(),
from.animate(&to, Procedure::Interpolate { progress: 0.5 }).unwrap(),
TransformList(Some(vec![TransformOperation::InterpolateMatrix {
from_list: from.clone(),
to_list: to.clone(),

View File

@ -5,16 +5,14 @@
use cssparser::SourceLocation;
use euclid::ScaleFactor;
use euclid::TypedSize2D;
use html5ever::LocalName;
use selectors::parser::{AncestorHashes, Selector};
use selectors::parser::LocalName as LocalNameSelector;
use servo_arc::Arc;
use servo_atoms::Atom;
use style::context::QuirksMode;
use style::media_queries::{Device, MediaType};
use style::properties::{PropertyDeclarationBlock, PropertyDeclaration};
use style::properties::{longhands, Importance};
use style::selector_map::{self, SelectorMap};
use style::selector_map::SelectorMap;
use style::selector_parser::{SelectorImpl, SelectorParser};
use style::shared_lock::SharedRwLock;
use style::stylesheets::StyleRule;