Bug 1488414 - Use decomposition to interpolate matched perspective transform operations. r=birtles a=pascalc
 author Emilio Cobos Álvarez Wed, 05 Sep 2018 13:35:06 +0000 changeset 492404 7f9b2799bcb3457a1da42c4057ffafcfb02e76cf parent 492403 3157946d732e919a60052f6bc124b312c70be1a5 child 492405 e43b9c1507d221650d7155607dec87b18752e5b5 push id 1815 push user ffxbld-merge push date Mon, 15 Oct 2018 10:40:45 +0000 treeherder mozilla-release@18d4c09e9378 [default view] [failures only] perfherder [talos] [build metrics] [platform microbench] (compared to previous push) reviewers birtles, pascalc bugs 1488414 milestone 63.0
Bug 1488414 - Use decomposition to interpolate matched perspective transform operations. r=birtles a=pascalc Looks like this produces sensible results for interpolation with 0, though I'm not really convinced about the results from, let's say, 1px to 2000px in the attached test-case, I would've expected a linear interpolation from that to go through normal length interpolation. css-transforms-1 says: > Two transform functions with the same name and the same number of arguments > are interpolated numerically without a former conversion. The calculated > value will be of the same transform function type with the same number of > arguments. > > Special rules apply to <matrix()>. Which is what we do... I was going to file a spec issue but turns out that it's already addressed in css-transforms-2: https://drafts.csswg.org/css-transforms-2/#interpolation-of-transform-functions Which says: > The transform functions <matrix()>, matrix3d() and perspective() get > converted into 4x4 matrices first and interpolated as defined in section > Interpolation of Matrices afterwards. Differential Revision: https://phabricator.services.mozilla.com/D4942
```--- a/servo/components/style/properties/helpers/animated_properties.mako.rs
+++ b/servo/components/style/properties/helpers/animated_properties.mako.rs
@@ -1291,19 +1291,37 @@ impl Animate for ComputedTransformOperat
Ok(TransformOperation::Rotate(
fa.animate(&ta, procedure)?
))
},
(
&TransformOperation::Perspective(ref fd),
&TransformOperation::Perspective(ref td),
) => {
-                Ok(TransformOperation::Perspective(
-                    fd.animate(td, procedure)?
-                ))
+                use values::computed::CSSPixelLength;
+                use values::generics::transform::create_perspective_matrix;
+
+                // From https://drafts.csswg.org/css-transforms-2/#interpolation-of-transform-functions:
+                //
+                //    The transform functions matrix(), matrix3d() and
+                //    perspective() get converted into 4x4 matrices first and
+                //    interpolated as defined in section Interpolation of
+                //    Matrices afterwards.
+                //
+                let from = create_perspective_matrix(fd.px());
+                let to = create_perspective_matrix(td.px());
+
+                let interpolated =
+                    Matrix3D::from(from).animate(&Matrix3D::from(to), procedure)?;
+
+                let decomposed = decompose_3d_matrix(interpolated)?;
+                let perspective_z = decomposed.perspective.2;
+                let used_value =
+                    if perspective_z == 0. { 0. } else { -1. / perspective_z };
+                Ok(TransformOperation::Perspective(CSSPixelLength::new(used_value)))
},
_ if self.is_translate() && other.is_translate() => {
self.to_translate_3d().animate(&other.to_translate_3d(), procedure)
}
_ if self.is_scale() && other.is_scale() => {
self.to_scale_3d().animate(&other.to_scale_3d(), procedure)
}
_ if self.is_rotate() && other.is_rotate() => {```
```--- a/servo/components/style/values/computed/transform.rs
+++ b/servo/components/style/values/computed/transform.rs
@@ -37,16 +37,17 @@ impl TransformOrigin {
LengthOrPercentage::Percentage(Percentage(0.5)),
Length::new(0.),
)
}
}

/// computed value of matrix3d()
pub type Matrix3D = generic::Matrix3D<Number>;
+
/// computed value of matrix()
pub type Matrix = generic::Matrix<Number>;

// we rustfmt_skip here because we want the matrices to look like
// matrices instead of being split across lines
#[cfg_attr(rustfmt, rustfmt_skip)]
impl Matrix3D {
#[inline]```