mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
Auto merge of #17162 - birtles:additive-smil, r=hiro
Support additive SMIL animation These are the Servo-side changes for [Bug 1355349](https://bugzilla.mozilla.org/show_bug.cgi?id=1355349). They have been reviewed by @hiikezoe. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/17162) <!-- Reviewable:end -->
This commit is contained in:
commit
d767e6046b
3 changed files with 167 additions and 1 deletions
|
@ -2185,6 +2185,22 @@ extern "C" {
|
||||||
RawServoAnimationValueBorrowed)
|
RawServoAnimationValueBorrowed)
|
||||||
-> bool;
|
-> bool;
|
||||||
}
|
}
|
||||||
|
extern "C" {
|
||||||
|
pub fn Servo_AnimationValues_Add(a: RawServoAnimationValueBorrowed,
|
||||||
|
b: RawServoAnimationValueBorrowed)
|
||||||
|
-> RawServoAnimationValueStrong;
|
||||||
|
}
|
||||||
|
extern "C" {
|
||||||
|
pub fn Servo_AnimationValues_Accumulate(a: RawServoAnimationValueBorrowed,
|
||||||
|
b: RawServoAnimationValueBorrowed,
|
||||||
|
count: u64)
|
||||||
|
-> RawServoAnimationValueStrong;
|
||||||
|
}
|
||||||
|
extern "C" {
|
||||||
|
pub fn Servo_AnimationValues_GetZeroValue(value_to_match:
|
||||||
|
RawServoAnimationValueBorrowed)
|
||||||
|
-> RawServoAnimationValueStrong;
|
||||||
|
}
|
||||||
extern "C" {
|
extern "C" {
|
||||||
pub fn Servo_AnimationValues_ComputeDistance(from:
|
pub fn Servo_AnimationValues_ComputeDistance(from:
|
||||||
RawServoAnimationValueBorrowed,
|
RawServoAnimationValueBorrowed,
|
||||||
|
|
|
@ -641,6 +641,24 @@ impl Animatable for AnimationValue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_zero_value(&self) -> Option<Self> {
|
||||||
|
match self {
|
||||||
|
% for prop in data.longhands:
|
||||||
|
% if prop.animatable:
|
||||||
|
% if prop.animation_value_type == "discrete":
|
||||||
|
&AnimationValue::${prop.camel_case}(_) => {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
% else:
|
||||||
|
&AnimationValue::${prop.camel_case}(ref base) => {
|
||||||
|
base.get_zero_value().map(AnimationValue::${prop.camel_case})
|
||||||
|
}
|
||||||
|
% endif
|
||||||
|
% endif
|
||||||
|
% endfor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
|
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
% for prop in data.longhands:
|
% for prop in data.longhands:
|
||||||
|
@ -697,6 +715,17 @@ pub trait Animatable: Sized {
|
||||||
self.add_weighted(other, count as f64, 1.0)
|
self.add_weighted(other, count as f64, 1.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a value that, when added with an underlying value, will produce the underlying
|
||||||
|
/// value. This is used for SMIL animation's "by-animation" where SMIL first interpolates from
|
||||||
|
/// the zero value to the 'by' value, and then adds the result to the underlying value.
|
||||||
|
///
|
||||||
|
/// This is not the necessarily the same as the initial value of a property. For example, the
|
||||||
|
/// initial value of 'stroke-width' is 1, but the zero value is 0, since adding 1 to the
|
||||||
|
/// underlying value will not produce the underlying value.
|
||||||
|
fn get_zero_value(&self) -> Option<Self> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
/// Compute distance between a value and another for a given property.
|
/// Compute distance between a value and another for a given property.
|
||||||
fn compute_distance(&self, _other: &Self) -> Result<f64, ()> { Err(()) }
|
fn compute_distance(&self, _other: &Self) -> Result<f64, ()> { Err(()) }
|
||||||
|
|
||||||
|
@ -746,6 +775,9 @@ impl Animatable for Au {
|
||||||
Ok(Au((self.0 as f64 * self_portion + other.0 as f64 * other_portion).round() as i32))
|
Ok(Au((self.0 as f64 * self_portion + other.0 as f64 * other_portion).round() as i32))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_zero_value(&self) -> Option<Self> { Some(Au(0)) }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
|
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
|
||||||
self.0.compute_distance(&other.0)
|
self.0.compute_distance(&other.0)
|
||||||
|
@ -795,6 +827,9 @@ impl Animatable for f32 {
|
||||||
Ok((*self as f64 * self_portion + *other as f64 * other_portion) as f32)
|
Ok((*self as f64 * self_portion + *other as f64 * other_portion) as f32)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_zero_value(&self) -> Option<Self> { Some(0.) }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
|
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
|
||||||
Ok((*self - *other).abs() as f64)
|
Ok((*self - *other).abs() as f64)
|
||||||
|
@ -808,6 +843,9 @@ impl Animatable for f64 {
|
||||||
Ok(*self * self_portion + *other * other_portion)
|
Ok(*self * self_portion + *other * other_portion)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_zero_value(&self) -> Option<Self> { Some(0.) }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
|
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
|
||||||
Ok((*self - *other).abs())
|
Ok((*self - *other).abs())
|
||||||
|
@ -821,6 +859,9 @@ impl Animatable for i32 {
|
||||||
Ok((*self as f64 * self_portion + *other as f64 * other_portion).round() as i32)
|
Ok((*self as f64 * self_portion + *other as f64 * other_portion).round() as i32)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_zero_value(&self) -> Option<Self> { Some(0) }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
|
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
|
||||||
Ok((*self - *other).abs() as f64)
|
Ok((*self - *other).abs() as f64)
|
||||||
|
@ -999,6 +1040,13 @@ impl Animatable for LengthOrPercentage {
|
||||||
.map(LengthOrPercentage::Percentage)
|
.map(LengthOrPercentage::Percentage)
|
||||||
}
|
}
|
||||||
(this, other) => {
|
(this, other) => {
|
||||||
|
// Special handling for zero values since these should not require calc().
|
||||||
|
if this.is_definitely_zero() {
|
||||||
|
return other.add_weighted(&other, 0., other_portion)
|
||||||
|
} else if other.is_definitely_zero() {
|
||||||
|
return this.add_weighted(self, self_portion, 0.)
|
||||||
|
}
|
||||||
|
|
||||||
let this: CalcLengthOrPercentage = From::from(this);
|
let this: CalcLengthOrPercentage = From::from(this);
|
||||||
let other: CalcLengthOrPercentage = From::from(other);
|
let other: CalcLengthOrPercentage = From::from(other);
|
||||||
this.add_weighted(&other, self_portion, other_portion)
|
this.add_weighted(&other, self_portion, other_portion)
|
||||||
|
@ -1007,6 +1055,9 @@ impl Animatable for LengthOrPercentage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_zero_value(&self) -> Option<Self> { Some(LengthOrPercentage::zero()) }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
|
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
|
||||||
match (*self, *other) {
|
match (*self, *other) {
|
||||||
|
@ -1079,6 +1130,18 @@ impl Animatable for LengthOrPercentageOrAuto {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_zero_value(&self) -> Option<Self> {
|
||||||
|
match *self {
|
||||||
|
LengthOrPercentageOrAuto::Length(_) |
|
||||||
|
LengthOrPercentageOrAuto::Percentage(_) |
|
||||||
|
LengthOrPercentageOrAuto::Calc(_) => {
|
||||||
|
Some(LengthOrPercentageOrAuto::Length(Au(0)))
|
||||||
|
},
|
||||||
|
LengthOrPercentageOrAuto::Auto => { None },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
|
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
|
||||||
match (*self, *other) {
|
match (*self, *other) {
|
||||||
|
@ -1149,6 +1212,18 @@ impl Animatable for LengthOrPercentageOrNone {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_zero_value(&self) -> Option<Self> {
|
||||||
|
match *self {
|
||||||
|
LengthOrPercentageOrNone::Length(_) |
|
||||||
|
LengthOrPercentageOrNone::Percentage(_) |
|
||||||
|
LengthOrPercentageOrNone::Calc(_) => {
|
||||||
|
Some(LengthOrPercentageOrNone::Length(Au(0)))
|
||||||
|
},
|
||||||
|
LengthOrPercentageOrNone::None => { None },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
|
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
|
||||||
match (*self, *other) {
|
match (*self, *other) {
|
||||||
|
@ -1223,7 +1298,8 @@ impl Animatable for FontWeight {
|
||||||
fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: 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 a = (*self as u32) as f64;
|
||||||
let b = (*other as u32) as f64;
|
let b = (*other as u32) as f64;
|
||||||
let weight = a * self_portion + b * other_portion;
|
const NORMAL: f64 = 400.;
|
||||||
|
let weight = (a - NORMAL) * self_portion + (b - NORMAL) * other_portion + NORMAL;
|
||||||
Ok(if weight < 150. {
|
Ok(if weight < 150. {
|
||||||
FontWeight::Weight100
|
FontWeight::Weight100
|
||||||
} else if weight < 250. {
|
} else if weight < 250. {
|
||||||
|
@ -1245,6 +1321,9 @@ impl Animatable for FontWeight {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_zero_value(&self) -> Option<Self> { Some(FontWeight::Weight400) }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
|
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
|
||||||
let a = (*self as u32) as f64;
|
let a = (*self as u32) as f64;
|
||||||
|
@ -1306,6 +1385,11 @@ impl Into<FontStretch> for f64 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Like std::macros::try!, but for Option<>.
|
||||||
|
macro_rules! option_try {
|
||||||
|
($e:expr) => (match $e { Some(e) => e, None => return None })
|
||||||
|
}
|
||||||
|
|
||||||
/// https://drafts.csswg.org/css-transitions/#animtype-simple-list
|
/// https://drafts.csswg.org/css-transitions/#animtype-simple-list
|
||||||
impl<H: Animatable, V: Animatable> Animatable for generic_position::Position<H, V> {
|
impl<H: Animatable, V: Animatable> Animatable for generic_position::Position<H, V> {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -1318,6 +1402,14 @@ impl<H: Animatable, V: Animatable> Animatable for generic_position::Position<H,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_zero_value(&self) -> Option<Self> {
|
||||||
|
Some(generic_position::Position {
|
||||||
|
horizontal: option_try!(self.horizontal.get_zero_value()),
|
||||||
|
vertical: option_try!(self.vertical.get_zero_value()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
|
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
|
||||||
self.compute_squared_distance(other).map(|sd| sd.sqrt())
|
self.compute_squared_distance(other).map(|sd| sd.sqrt())
|
||||||
|
@ -2493,6 +2585,9 @@ impl Animatable for TransformList {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_zero_value(&self) -> Option<Self> { Some(TransformList(None)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, U> Animatable for Either<T, U>
|
impl<T, U> Animatable for Either<T, U>
|
||||||
|
@ -2514,6 +2609,14 @@ impl<T, U> Animatable for Either<T, U>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_zero_value(&self) -> Option<Self> {
|
||||||
|
match *self {
|
||||||
|
Either::First(ref this) => { this.get_zero_value().map(Either::First) },
|
||||||
|
Either::Second(ref this) => { this.get_zero_value().map(Either::Second) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
|
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
|
@ -2616,6 +2719,11 @@ impl Animatable for IntermediateRGBA {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn get_zero_value(&self) -> Option<Self> {
|
||||||
|
Some(IntermediateRGBA::new(0., 0., 0., 1.))
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
|
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
|
||||||
self.compute_squared_distance(other).map(|sq| sq.sqrt())
|
self.compute_squared_distance(other).map(|sq| sq.sqrt())
|
||||||
|
|
|
@ -313,6 +313,48 @@ pub extern "C" fn Servo_AnimationValues_IsInterpolable(from: RawServoAnimationVa
|
||||||
from_value.interpolate(to_value, 0.5).is_ok()
|
from_value.interpolate(to_value, 0.5).is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn Servo_AnimationValues_Add(a: RawServoAnimationValueBorrowed,
|
||||||
|
b: RawServoAnimationValueBorrowed)
|
||||||
|
-> RawServoAnimationValueStrong
|
||||||
|
{
|
||||||
|
let a_value = AnimationValue::as_arc(&a);
|
||||||
|
let b_value = AnimationValue::as_arc(&b);
|
||||||
|
if let Ok(value) = a_value.add(b_value) {
|
||||||
|
Arc::new(value).into_strong()
|
||||||
|
} else {
|
||||||
|
RawServoAnimationValueStrong::null()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn Servo_AnimationValues_Accumulate(a: RawServoAnimationValueBorrowed,
|
||||||
|
b: RawServoAnimationValueBorrowed,
|
||||||
|
count: u64)
|
||||||
|
-> RawServoAnimationValueStrong
|
||||||
|
{
|
||||||
|
let a_value = AnimationValue::as_arc(&a);
|
||||||
|
let b_value = AnimationValue::as_arc(&b);
|
||||||
|
if let Ok(value) = a_value.accumulate(b_value, count) {
|
||||||
|
Arc::new(value).into_strong()
|
||||||
|
} else {
|
||||||
|
RawServoAnimationValueStrong::null()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn Servo_AnimationValues_GetZeroValue(
|
||||||
|
value_to_match: RawServoAnimationValueBorrowed)
|
||||||
|
-> RawServoAnimationValueStrong
|
||||||
|
{
|
||||||
|
let value_to_match = AnimationValue::as_arc(&value_to_match);
|
||||||
|
if let Some(zero_value) = value_to_match.get_zero_value() {
|
||||||
|
Arc::new(zero_value).into_strong()
|
||||||
|
} else {
|
||||||
|
RawServoAnimationValueStrong::null()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn Servo_AnimationValues_ComputeDistance(from: RawServoAnimationValueBorrowed,
|
pub extern "C" fn Servo_AnimationValues_ComputeDistance(from: RawServoAnimationValueBorrowed,
|
||||||
to: RawServoAnimationValueBorrowed)
|
to: RawServoAnimationValueBorrowed)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue