Bug 1505200 - Part 1: Rewrite the interpolation of Rotate to return correct type. r=birtles

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 <angle>.
4. Otherwise, we do interpolation by 3D rotation.

Differential Revision: https://phabricator.services.mozilla.com/D11247

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Boris Chiou 2018-11-12 23:17:19 +00:00
Родитель 97ccc8c012
Коммит 5f3b39da88
3 изменённых файлов: 55 добавлений и 67 удалений

Просмотреть файл

@ -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<Self, ()> {
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 <angle>
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)))
}
}

Просмотреть файл

@ -1,40 +1,8 @@
[rotate-interpolation.html]
[Animation between "45deg" and "-1 1 0 60deg" at progress 1]
expected: FAIL
[Animation between "none" and "7 -8 9 400grad" at progress -1]
expected: FAIL
bug: https://github.com/w3c/csswg-drafts/issues/3290
[Animation between "none" and "7 -8 9 400grad" at progress 0]
expected: FAIL
[Animation between "none" and "7 -8 9 400grad" at progress 0.125]
expected: FAIL
[Animation between "none" and "7 -8 9 400grad" at progress 0.875]
expected: FAIL
[Animation between "none" and "7 -8 9 400grad" at progress 1]
expected: FAIL
[Animation between "none" and "7 -8 9 400grad" at progress 2]
expected: FAIL
[Animation between "none" and "none" at progress -1]
expected: FAIL
[Animation between "none" and "none" at progress 0]
expected: FAIL
[Animation between "none" and "none" at progress 0.125]
expected: FAIL
[Animation between "none" and "none" at progress 0.875]
expected: FAIL
[Animation between "none" and "none" at progress 1]
expected: FAIL
[Animation between "none" and "none" at progress 2]
expected: FAIL
bug: https://github.com/w3c/csswg-drafts/issues/3290

Просмотреть файл

@ -1,9 +1,12 @@
[scale-interpolation.html]
[Animation between "26 17 9" and "2" at progress 1]
expected: FAIL
bug: https://github.com/w3c/csswg-drafts/issues/3290
[Animation between "none" and "4 3 2" at progress 0]
expected: FAIL
bug: https://github.com/w3c/csswg-drafts/issues/3290
[Animation between "26 17 9" and "2 1" at progress 1]
expected: FAIL
bug: https://github.com/w3c/csswg-drafts/issues/3290