mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
Rewrite decomposition of 2d matrix.
The implementation of 2d matrix decomposition in Servo matches that in spec, but its result is really different from that in Gecko, so the visual results on the main thread and on the compositor thread are really different and we got many test failures. Therefore, let's write a different algorithm of decomposition of 2d matrix for Stylo, and keep the original one for Servo. The output of new implemented 2d matrix decomposition is a Decomposed3DMatrix, so we can reuse the interpolation and re-composition code. (Just like what we do in Gecko.)
This commit is contained in:
parent
9c338a2929
commit
9b76cd9d1c
1 changed files with 70 additions and 0 deletions
|
@ -1399,6 +1399,7 @@ impl ComputeSquaredDistance for MatrixDecomposed2D {
|
|||
}
|
||||
|
||||
impl Animate for ComputedMatrix {
|
||||
#[cfg(feature = "servo")]
|
||||
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
|
||||
if self.is_3d() || other.is_3d() {
|
||||
let decomposed_from = decompose_3d_matrix(*self);
|
||||
|
@ -1419,6 +1420,25 @@ impl Animate for ComputedMatrix {
|
|||
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 {
|
||||
|
@ -1830,6 +1850,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.
|
||||
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