Bug 1424134 - Part 3: Implement ComputeSquaredDistance for individual transforms. r=birtles

We manually implement ComputeSquaredDistance for Translate, Rotate, and
Scale because we have to handle mismatch cases, and actually we don't
need to implement it for specified types.

Depends on D11934

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Boris Chiou 2018-11-16 18:58:41 +00:00
Родитель 40a2db875c
Коммит 2718fd0897
4 изменённых файлов: 132 добавлений и 17 удалений

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

@ -6,6 +6,7 @@ prefs =
dom.animations-api.implicit-keyframes.enabled=true
dom.animations-api.timelines.enabled=true
layout.css.motion-path.enabled=true
layout.css.individual-transform.enabled=true
# Support files for chrome tests that we want to load over HTTP need
# to go in here, not chrome.ini.
support-files =

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

@ -339,5 +339,66 @@ test(function(t) {
'distance of transform lists');
}, 'Test distance of mismatched transform lists with skew function');
// Individual transforms
test(function(t) {
var target = addDiv(t);
var dist = getDistance(target, 'translate', '50px', 'none');
assert_equals(dist, Math.sqrt(50 * 50), 'distance of 2D translate and none');
}, 'Test distance of 2D translate property with none');
test(function(t) {
var target = addDiv(t);
var dist = getDistance(target, 'translate', '10px 30px', '50px');
assert_equals(dist, Math.sqrt(40 * 40 + 30 * 30), 'distance of 2D translate');
}, 'Test distance of 2D translate property');
test(function(t) {
var target = addDiv(t);
var dist = getDistance(target, 'translate', '10px 30px 50px', '50px');
assert_equals(dist, Math.sqrt(40 * 40 + 30 * 30 + 50 * 50),
'distance of 3D translate');
}, 'Test distance of 3D translate property');
test(function(t) {
var target = addDiv(t);
var dist = getDistance(target, 'scale', '2', 'none');
assert_equals(dist, Math.sqrt(1 + 1), 'distance of 2D scale and none');
}, 'Test distance of 2D scale property with none');
test(function(t) {
var target = addDiv(t);
var dist = getDistance(target, 'scale', '3', '1 1');
assert_equals(dist, Math.sqrt(2 * 2 + 2 * 2), 'distance of 2D scale');
}, 'Test distance of 2D scale property');
test(function(t) {
var target = addDiv(t);
var dist = getDistance(target, 'scale', '3 2 2', '1 1');
assert_equals(dist, Math.sqrt(2 * 2 + 1 * 1 + 1 * 1),
'distance of 3D scale');
}, 'Test distance of 3D scale property');
test(function(t) {
var target = addDiv(t);
var dist = getDistance(target, 'rotate', '180deg', 'none');
assert_equals(dist, Math.PI, 'distance of 2D rotate and none');
}, 'Test distance of 2D rotate property with none');
test(function(t) {
var target = addDiv(t);
var dist = getDistance(target, 'rotate', '180deg', '90deg');
assert_equals(dist, Math.PI / 2.0, 'distance of 2D rotate');
}, 'Test distance of 2D rotate property');
test(function(t) {
var target = addDiv(t);
var dist = getDistance(target, 'rotate', 'z 90deg', 'x 90deg');
let q1 = getQuaternion([0, 0, 1], Math.PI / 2.0);
let q2 = getQuaternion([1, 0, 0], Math.PI / 2.0);
assert_approx_equals(dist, computeRotateDistance(q1, q2), EPSILON,
'distance of 3D rotate');
}, 'Test distance of 3D rotate property');
</script>
</html>

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

@ -1309,19 +1309,8 @@ impl ComputeSquaredDistance for ComputedTransformOperation {
&TransformOperation::Rotate3D(fx, fy, fz, fa),
&TransformOperation::Rotate3D(tx, ty, tz, ta),
) => {
let (fx, fy, fz, angle1) =
transform::get_normalized_vector_and_angle(fx, fy, fz, fa);
let (tx, ty, tz, angle2) =
transform::get_normalized_vector_and_angle(tx, ty, tz, ta);
if (fx, fy, fz) == (tx, ty, tz) {
angle1.compute_squared_distance(&angle2)
} else {
let v1 = DirectionVector::new(fx, fy, fz);
let v2 = DirectionVector::new(tx, ty, tz);
let q1 = Quaternion::from_direction_and_angle(&v1, angle1.radians64());
let q2 = Quaternion::from_direction_and_angle(&v2, angle2.radians64());
q1.compute_squared_distance(&q2)
}
Rotate::Rotate3D(fx, fy, fz, fa)
.compute_squared_distance(&Rotate::Rotate3D(tx, ty, tz, ta))
},
(
&TransformOperation::RotateX(fa),
@ -1390,7 +1379,7 @@ impl ComputedRotate {
//
// If the axis is unspecified, it defaults to "0 0 1"
match *self {
Rotate::None => unreachable!("None is handled by the caller"),
Rotate::None => (0., 0., 1., Angle::zero()),
Rotate::Rotate3D(rx, ry, rz, angle) => (rx, ry, rz, angle),
Rotate::Rotate(angle) => (0., 0., 1., angle),
}
@ -1459,6 +1448,49 @@ impl Animate for ComputedRotate {
}
}
impl ComputeSquaredDistance for ComputedRotate {
#[inline]
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
match (self, other) {
(&Rotate::None, &Rotate::None) => Ok(SquaredDistance::from_sqrt(0.)),
(&Rotate::Rotate3D(_, _, _, a), &Rotate::None) |
(&Rotate::None, &Rotate::Rotate3D(_, _, _, a)) => {
a.compute_squared_distance(&Angle::zero())
},
(&Rotate::Rotate3D(_, ..), _) | (_, &Rotate::Rotate3D(_, ..)) => {
let (from, to) = (self.resolve(), other.resolve());
let (mut fx, mut fy, mut fz, angle1) =
transform::get_normalized_vector_and_angle(from.0, from.1, from.2, from.3);
let (mut tx, mut ty, mut tz, angle2) =
transform::get_normalized_vector_and_angle(to.0, to.1, to.2, to.3);
if angle1 == Angle::zero() {
fx = tx;
fy = ty;
fz = tz;
} else if angle2 == Angle::zero() {
tx = fx;
ty = fy;
tz = fz;
}
if (fx, fy, fz) == (tx, ty, tz) {
angle1.compute_squared_distance(&angle2)
} else {
let v1 = DirectionVector::new(fx, fy, fz);
let v2 = DirectionVector::new(tx, ty, tz);
let q1 = Quaternion::from_direction_and_angle(&v1, angle1.radians64());
let q2 = Quaternion::from_direction_and_angle(&v2, angle2.radians64());
q1.compute_squared_distance(&q2)
}
},
(&Rotate::Rotate(_), _) | (_, &Rotate::Rotate(_)) => {
self.resolve().3.compute_squared_distance(&other.resolve().3)
},
}
}
}
/// <https://drafts.csswg.org/css-transforms-2/#propdef-translate>
impl ComputedTranslate {
fn resolve(&self) -> (LengthOrPercentage, LengthOrPercentage, Length) {
@ -1500,6 +1532,18 @@ impl Animate for ComputedTranslate {
}
}
impl ComputeSquaredDistance for ComputedTranslate {
#[inline]
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
let (from, to) = (self.resolve(), other.resolve());
Ok(
from.0.compute_squared_distance(&to.0)? +
from.1.compute_squared_distance(&to.1)? +
from.2.compute_squared_distance(&to.2)?
)
}
}
/// <https://drafts.csswg.org/css-transforms-2/#propdef-scale>
impl ComputedScale {
fn resolve(&self) -> (Number, Number, Number) {
@ -1554,3 +1598,15 @@ impl Animate for ComputedScale {
}
}
}
impl ComputeSquaredDistance for ComputedScale {
#[inline]
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
let (from, to) = (self.resolve(), other.resolve());
Ok(
from.0.compute_squared_distance(&to.0)? +
from.1.compute_squared_distance(&to.1)? +
from.2.compute_squared_distance(&to.2)?
)
}
}

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

@ -530,7 +530,6 @@ pub fn get_normalized_vector_and_angle<T: Zero>(
#[derive(
Clone,
ComputeSquaredDistance,
Copy,
Debug,
MallocSizeOf,
@ -600,7 +599,6 @@ where
#[derive(
Clone,
ComputeSquaredDistance,
Copy,
Debug,
MallocSizeOf,
@ -649,7 +647,6 @@ impl<Number: ToCss + PartialEq> ToCss for Scale<Number> {
#[derive(
Clone,
ComputeSquaredDistance,
Debug,
MallocSizeOf,
PartialEq,