From 0b9ecbccfeb15e0ee73f7bbf218550d6cfbc2d28 Mon Sep 17 00:00:00 2001 From: Boris Chiou Date: Mon, 12 Nov 2018 23:17:19 +0000 Subject: [PATCH] style: Rewrite the interpolation of Rotate to return correct type. The original implementation always returns Rotate::Rotate3D, but it is not correct, so we have to rewrite it: 1. If both from value and to value are none, we don't have to convert it into identity value, so just return None. 2. If one of the value is none, we replace it with an identity value based on the other one's rotate axis. 3. If we only have 2D rotation, we just animate the . 4. Otherwise, we do interpolation by 3D rotation. Differential Revision: https://phabricator.services.mozilla.com/D11247 --- .../helpers/animated_properties.mako.rs | 83 +++++++++++-------- 1 file changed, 50 insertions(+), 33 deletions(-) diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index 5ff4a10c3c0..4efab0bc60d 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -2108,7 +2108,7 @@ impl ComputedRotate { // // If the axis is unspecified, it defaults to "0 0 1" match *self { - Rotate::None => (0., 0., 1., Angle::zero()), + Rotate::None => unreachable!("None is handled by the caller"), Rotate::Rotate3D(rx, ry, rz, angle) => (rx, ry, rz, angle), Rotate::Rotate(angle) => (0., 0., 1., angle), } @@ -2122,41 +2122,58 @@ impl Animate for ComputedRotate { other: &Self, procedure: Procedure, ) -> Result { - let (from, to) = (self.resolve(), other.resolve()); + match (self, other) { + (&Rotate::None, &Rotate::None) => Ok(Rotate::None), + (&Rotate::Rotate3D(fx, fy, fz, fa), &Rotate::None) => { + // No need to normalize `none`, so animate angle directly. + Ok(Rotate::Rotate3D(fx, fy, fz, fa.animate(&Angle::zero(), procedure)?)) + }, + (&Rotate::None, &Rotate::Rotate3D(tx, ty, tz, ta)) => { + // No need to normalize `none`, so animate angle directly. + Ok(Rotate::Rotate3D(tx, ty, tz, Angle::zero().animate(&ta, procedure)?)) + }, + (&Rotate::Rotate3D(_, ..), _) | (_, &Rotate::Rotate3D(_, ..)) => { + let (from, to) = (self.resolve(), other.resolve()); + let (mut fx, mut fy, mut fz, fa) = + transform::get_normalized_vector_and_angle(from.0, from.1, from.2, from.3); + let (mut tx, mut ty, mut tz, ta) = + transform::get_normalized_vector_and_angle(to.0, to.1, to.2, to.3); - let (mut fx, mut fy, mut fz, fa) = - transform::get_normalized_vector_and_angle(from.0, from.1, from.2, from.3); - let (mut tx, mut ty, mut tz, ta) = - transform::get_normalized_vector_and_angle(to.0, to.1, to.2, to.3); + if fa == Angle::from_degrees(0.) { + fx = tx; + fy = ty; + fz = tz; + } else if ta == Angle::from_degrees(0.) { + tx = fx; + ty = fy; + tz = fz; + } - if fa == Angle::from_degrees(0.) { - fx = tx; - fy = ty; - fz = tz; - } else if ta == Angle::from_degrees(0.) { - tx = fx; - ty = fy; - tz = fz; + 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))) + }, + (&Rotate::Rotate(_), _) | (_, &Rotate::Rotate(_)) => { + // If this is a 2D rotation, we just animate the + let (from, to) = (self.resolve().3, other.resolve().3); + Ok(Rotate::Rotate(from.animate(&to, procedure)?)) + }, } - - 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))) } }