Bug 1488414 - Use decomposition to interpolate matched perspective transform operations. r=birtles a=pascalc
authorEmilio Cobos Álvarez <emilio@crisal.io>
Wed, 05 Sep 2018 13:35:06 +0000
changeset 492404 7f9b2799bcb3457a1da42c4057ffafcfb02e76cf
parent 492403 3157946d732e919a60052f6bc124b312c70be1a5
child 492405 e43b9c1507d221650d7155607dec87b18752e5b5
push id1815
push userffxbld-merge
push dateMon, 15 Oct 2018 10:40:45 +0000
treeherdermozilla-release@18d4c09e9378 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbirtles, pascalc
bugs1488414
milestone63.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
servo/components/style/properties/helpers/animated_properties.mako.rs
servo/components/style/values/computed/transform.rs
--- 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]