Implement Animate trait for individual transforms

This commit is contained in:
CJ Ku 2018-01-25 12:53:01 +09:00 committed by Brian Birtles
parent 9a62c0bf02
commit 8a4661b829
5 changed files with 130 additions and 40 deletions

View file

@ -46,7 +46,10 @@ use values::computed::ToComputedValue;
use values::computed::transform::{DirectionVector, Matrix, Matrix3D};
use values::computed::transform::TransformOperation as ComputedTransformOperation;
use values::computed::transform::Transform as ComputedTransform;
use values::generics::transform::{self, Transform, TransformOperation};
use values::computed::transform::Rotate as ComputedRotate;
use values::computed::transform::Translate as ComputedTranslate;
use values::computed::transform::Scale as ComputedScale;
use values::generics::transform::{self, Rotate, Translate, Scale, Transform, TransformOperation};
use values::distance::{ComputeSquaredDistance, SquaredDistance};
#[cfg(feature = "gecko")] use values::generics::FontSettings as GenericFontSettings;
#[cfg(feature = "gecko")] use values::generics::FontSettingTag as GenericFontSettingTag;
@ -2269,6 +2272,129 @@ impl Matrix3D {
}
}
/// <https://drafts.csswg.org/css-transforms-2/#propdef-rotate>
impl ComputedRotate {
fn fill_unspecified(rotate: &ComputedRotate) -> Result<(Number, Number, Number, Angle), ()> {
// According to the spec:
// https://drafts.csswg.org/css-transforms-2/#individual-transforms
//
// If the axis is unspecified, it defaults to "0 0 1"
match *rotate {
Rotate::None =>
Ok((0., 0., 1., Angle::zero())),
Rotate::Rotate3D(rx, ry, rz, angle) => Ok((rx, ry, rz, angle)),
Rotate::Rotate(angle) => Ok((0., 0., 1., angle)),
}
}
}
impl Animate for ComputedRotate {
#[inline]
fn animate(
&self,
other: &Self,
procedure: Procedure,
) -> Result<Self, ()> {
let from = ComputedRotate::fill_unspecified(self)?;
let to = ComputedRotate::fill_unspecified(other)?;
let (fx, fy, fz, fa) = transform::get_normalized_vector_and_angle(from.0, from.1, from.2, from.3);
let (tx, ty, tz, ta) = transform::get_normalized_vector_and_angle(to.0, to.1, to.2, to.3);
if (fx, fy, fz) == (tx, ty, tz) {
return Ok(Rotate::Rotate3D(fx, fy, fz, fa.animate(&ta, procedure)?));
}
let fv = DirectionVector::new(fx, fy, fz);
let tv = DirectionVector::new(tx, ty, tz);
let fq = Quaternion::from_direction_and_angle(&fv, fa.radians64());
let tq = Quaternion::from_direction_and_angle(&tv, ta.radians64());
let rq = Quaternion::animate(&fq, &tq, procedure)?;
let (x, y, z, angle) =
transform::get_normalized_vector_and_angle(rq.0 as f32,
rq.1 as f32,
rq.2 as f32,
rq.3.acos() as f32 *2.0);
Ok(Rotate::Rotate3D(x, y, z, Angle::from_radians(angle)))
}
}
/// <https://drafts.csswg.org/css-transforms-2/#propdef-translate>
impl ComputedTranslate {
fn fill_unspecified(translate: &ComputedTranslate)
-> Result<(LengthOrPercentage, LengthOrPercentage, Length), ()> {
// According to the spec:
// https://drafts.csswg.org/css-transforms-2/#individual-transforms
//
// Unspecified translations default to 0px
match *translate {
Translate::None => {
Ok((LengthOrPercentage::Length(Length::zero()),
LengthOrPercentage::Length(Length::zero()),
Length::zero()))
},
Translate::Translate3D(tx, ty, tz) => Ok((tx, ty, tz)),
Translate::Translate(tx, ty) => Ok((tx, ty, Length::zero())),
Translate::TranslateX(tx) => Ok((tx, LengthOrPercentage::Length(Length::zero()), Length::zero())),
}
}
}
impl Animate for ComputedTranslate {
#[inline]
fn animate(
&self,
other: &Self,
procedure: Procedure,
) -> Result<Self, ()> {
let from = ComputedTranslate::fill_unspecified(self)?;
let to = ComputedTranslate::fill_unspecified(other)?;
Ok(Translate::Translate3D(from.0.animate(&to.0, procedure)?,
from.1.animate(&to.1, procedure)?,
from.2.animate(&to.2, procedure)?))
}
}
/// <https://drafts.csswg.org/css-transforms-2/#propdef-scale>
impl ComputedScale {
fn fill_unspecified(scale: &ComputedScale)
-> Result<(Number, Number, Number), ()> {
// According to the spec:
// https://drafts.csswg.org/css-transforms-2/#individual-transforms
//
// Unspecified scales default to 1
match *scale {
Scale::None => Ok((1.0, 1.0, 1.0)),
Scale::Scale3D(sx, sy, sz) => Ok((sx, sy, sz)),
Scale::Scale(sx, sy) => Ok((sx, sy, 1.)),
Scale::ScaleX(sx) => Ok((sx, 1., 1.)),
}
}
}
impl Animate for ComputedScale {
#[inline]
fn animate(
&self,
other: &Self,
procedure: Procedure,
) -> Result<Self, ()> {
let from = ComputedScale::fill_unspecified(self)?;
let to = ComputedScale::fill_unspecified(other)?;
if procedure == Procedure::Add {
// scale(x1,y1,z1)*scale(x2,y2,z2) = scale(x1*x2, y1*y2, z1*z2)
return Ok(Scale::Scale3D(from.0 * to.0, from.1 * to.1, from.2 * to.2));
}
Ok(Scale::Scale3D(animate_multiplicative_factor(from.0, to.0, procedure)?,
animate_multiplicative_factor(from.1, to.1, procedure)?,
animate_multiplicative_factor(from.2, to.2, procedure)?))
}
}
/// <https://drafts.csswg.org/css-transforms/#interpolation-of-transforms>
impl Animate for ComputedTransform {
#[inline]

View file

@ -669,7 +669,7 @@ pub fn get_normalized_vector_and_angle<T: Zero>(
}
}
#[derive(Animate, ComputeSquaredDistance, ToAnimatedZero, ToComputedValue)]
#[derive(ComputeSquaredDistance, ToAnimatedZero, ToComputedValue)]
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)]
/// A value of the `Rotate` property
///
@ -683,7 +683,7 @@ pub enum Rotate<Number, Angle> {
Rotate3D(Number, Number, Number, Angle),
}
#[derive(Animate, ComputeSquaredDistance, ToAnimatedZero, ToComputedValue)]
#[derive(ComputeSquaredDistance, ToAnimatedZero, ToComputedValue)]
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)]
/// A value of the `Scale` property
///
@ -699,7 +699,7 @@ pub enum Scale<Number> {
Scale3D(Number, Number, Number),
}
#[derive(Animate, ComputeSquaredDistance, ToAnimatedZero, ToComputedValue)]
#[derive(ComputeSquaredDistance, ToAnimatedZero, ToComputedValue)]
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)]
/// A value of the `Translate` property
///