mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
Auto merge of #18197 - BorisChiou:stylo/transform/2dmatrix, r=birtles
stylo: Bug 1387990 - Fix the interpolation of 2d matrix. Write a 2d matrix decomposition for Gecko, so the visual results and test results could match those in Gecko. In long-term, we should let Gecko follow the spec, so we can drop the redundant implementation. --- - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix [Bug 1387990](https://bugzilla.mozilla.org/show_bug.cgi?id=1387990). - [X] These changes do not require tests because these patches fix the test failures in Gecko and we have tests already in Gecko. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/18197) <!-- Reviewable:end -->
This commit is contained in:
commit
4077953cf5
1 changed files with 82 additions and 0 deletions
|
@ -1399,6 +1399,7 @@ impl ComputeSquaredDistance for MatrixDecomposed2D {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Animate for ComputedMatrix {
|
impl Animate for ComputedMatrix {
|
||||||
|
#[cfg(feature = "servo")]
|
||||||
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
|
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
|
||||||
if self.is_3d() || other.is_3d() {
|
if self.is_3d() || other.is_3d() {
|
||||||
let decomposed_from = decompose_3d_matrix(*self);
|
let decomposed_from = decompose_3d_matrix(*self);
|
||||||
|
@ -1419,10 +1420,30 @@ impl Animate for ComputedMatrix {
|
||||||
Ok(ComputedMatrix::from(this.animate(&other, procedure)?))
|
Ok(ComputedMatrix::from(this.animate(&other, procedure)?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
|
||||||
|
let (from, to) = if self.is_3d() || other.is_3d() {
|
||||||
|
(decompose_3d_matrix(*self), decompose_3d_matrix(*other))
|
||||||
|
} else {
|
||||||
|
(decompose_2d_matrix(self), decompose_2d_matrix(other))
|
||||||
|
};
|
||||||
|
match (from, to) {
|
||||||
|
(Ok(from), Ok(to)) => {
|
||||||
|
Ok(ComputedMatrix::from(from.animate(&to, procedure)?))
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
let (this_weight, other_weight) = procedure.weights();
|
||||||
|
let result = if this_weight > other_weight { *self } else { *other };
|
||||||
|
Ok(result)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComputeSquaredDistance for ComputedMatrix {
|
impl ComputeSquaredDistance for ComputedMatrix {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[cfg(feature = "servo")]
|
||||||
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
|
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
|
||||||
if self.is_3d() || other.is_3d() {
|
if self.is_3d() || other.is_3d() {
|
||||||
let from = decompose_3d_matrix(*self)?;
|
let from = decompose_3d_matrix(*self)?;
|
||||||
|
@ -1434,6 +1455,17 @@ impl ComputeSquaredDistance for ComputedMatrix {
|
||||||
from.compute_squared_distance(&to)
|
from.compute_squared_distance(&to)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
|
||||||
|
let (from, to) = if self.is_3d() || other.is_3d() {
|
||||||
|
(decompose_3d_matrix(*self)?, decompose_3d_matrix(*other)?)
|
||||||
|
} else {
|
||||||
|
(decompose_2d_matrix(self)?, decompose_2d_matrix(other)?)
|
||||||
|
};
|
||||||
|
from.compute_squared_distance(&to)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ComputedMatrix> for MatrixDecomposed2D {
|
impl From<ComputedMatrix> for MatrixDecomposed2D {
|
||||||
|
@ -1830,6 +1862,56 @@ fn decompose_3d_matrix(mut matrix: ComputedMatrix) -> Result<MatrixDecomposed3D,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Decompose a 2D matrix for Gecko.
|
||||||
|
// Use the algorithm from nsStyleTransformMatrix::Decompose2DMatrix() in Gecko.
|
||||||
|
#[cfg(feature = "gecko")]
|
||||||
|
fn decompose_2d_matrix(matrix: &ComputedMatrix) -> Result<MatrixDecomposed3D, ()> {
|
||||||
|
// The index is column-major, so the equivalent transform matrix is:
|
||||||
|
// | m11 m21 0 m41 | => | m11 m21 | and translate(m41, m42)
|
||||||
|
// | m12 m22 0 m42 | | m12 m22 |
|
||||||
|
// | 0 0 1 0 |
|
||||||
|
// | 0 0 0 1 |
|
||||||
|
let (mut m11, mut m12) = (matrix.m11, matrix.m12);
|
||||||
|
let (mut m21, mut m22) = (matrix.m21, matrix.m22);
|
||||||
|
if m11 * m22 == m12 * m21 {
|
||||||
|
// singular matrix
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut scale_x = (m11 * m11 + m12 * m12).sqrt();
|
||||||
|
m11 /= scale_x;
|
||||||
|
m12 /= scale_x;
|
||||||
|
|
||||||
|
let mut shear_xy = m11 * m21 + m12 * m22;
|
||||||
|
m21 -= m11 * shear_xy;
|
||||||
|
m22 -= m12 * shear_xy;
|
||||||
|
|
||||||
|
let scale_y = (m21 * m21 + m22 * m22).sqrt();
|
||||||
|
m21 /= scale_y;
|
||||||
|
m22 /= scale_y;
|
||||||
|
shear_xy /= scale_y;
|
||||||
|
|
||||||
|
let determinant = m11 * m22 - m12 * m21;
|
||||||
|
debug_assert!(0.99 < determinant.abs() && determinant.abs() < 1.01,
|
||||||
|
"determinant should now be 1 or -1");
|
||||||
|
|
||||||
|
if determinant < 0. {
|
||||||
|
m11 = -m11;
|
||||||
|
m12 = -m12;
|
||||||
|
shear_xy = -shear_xy;
|
||||||
|
scale_x = -scale_x;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(MatrixDecomposed3D {
|
||||||
|
translate: Translate3D(matrix.m41, matrix.m42, 0.),
|
||||||
|
scale: Scale3D(scale_x, scale_y, 1.),
|
||||||
|
skew: Skew(shear_xy, 0., 0.),
|
||||||
|
perspective: Perspective(0., 0., 0., 1.),
|
||||||
|
quaternion: Quaternion::from_direction_and_angle(&DirectionVector::new(0., 0., 1.),
|
||||||
|
m12.atan2(m11) as f64)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Combine 2 point.
|
// Combine 2 point.
|
||||||
fn combine(a: [f32; 3], b: [f32; 3], ascl: f32, bscl: f32) -> [f32; 3] {
|
fn combine(a: [f32; 3], b: [f32; 3], ascl: f32, bscl: f32) -> [f32; 3] {
|
||||||
[
|
[
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue