From 6dcf9b763060d126d520843cb877c49488728edb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 5 Sep 2018 13:35:06 +0000 Subject: [PATCH] style: Use decomposition to interpolate matched perspective transform operations. 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 . 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 , 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 --- .../helpers/animated_properties.mako.rs | 24 ++++++++++++++++--- components/style/values/computed/transform.rs | 1 + 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index f6277a21271..437232d386a 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -1296,9 +1296,27 @@ impl Animate for ComputedTransformOperation { &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) diff --git a/components/style/values/computed/transform.rs b/components/style/values/computed/transform.rs index bbf710c4295..a2849a0d4b3 100644 --- a/components/style/values/computed/transform.rs +++ b/components/style/values/computed/transform.rs @@ -42,6 +42,7 @@ impl TransformOrigin { /// computed value of matrix3d() pub type Matrix3D = generic::Matrix3D; + /// computed value of matrix() pub type Matrix = generic::Matrix;