Bug 1424134 - Part 4: Expand the mako code of Matrix3D and move them into transform.rs. r=emilio
authorBoris Chiou <boris.chiou@gmail.com>
Fri, 16 Nov 2018 19:29:28 +0000
changeset 503296 dbc9d48aa60b8d31cc1ac90fe41f1fc386ff77cb
parent 503295 fbf6efa9b8ecb9697ec385a96b4a5854b11ad21c
child 503297 2c3b27812cbce5ed4514753e529e4fb4d2ca3d4a
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersemilio
bugs1424134
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1424134 - Part 4: Expand the mako code of Matrix3D and move them into transform.rs. r=emilio Although the methods of Matrix3D in animated_properties.mako.rs could be simplified by mako, it's a little bit hard to read because they are far from the usage and definition. Therefore, we move them to the definition of computed::Matrix3D and expand the mako. Depends on D11935 Differential Revision: https://phabricator.services.mozilla.com/D11961
servo/components/style/properties/helpers/animated_properties.mako.rs
servo/components/style/values/animated/transform.rs
servo/components/style/values/computed/transform.rs
--- a/servo/components/style/properties/helpers/animated_properties.mako.rs
+++ b/servo/components/style/properties/helpers/animated_properties.mako.rs
@@ -18,24 +18,21 @@ use crate::properties::longhands;
 use crate::properties::longhands::visibility::computed_value::T as Visibility;
 use crate::properties::LonghandId;
 use servo_arc::Arc;
 use smallvec::SmallVec;
 use std::ptr;
 use std::mem::{self, ManuallyDrop};
 use crate::hash::FxHashMap;
 use super::ComputedValues;
-use crate::values::CSSFloat;
 use crate::values::animated::{Animate, Procedure, ToAnimatedValue, ToAnimatedZero};
 use crate::values::animated::effects::Filter as AnimatedFilter;
-use crate::values::animated::transform::{Perspective, Scale3D, Translate3D};
 #[cfg(feature = "gecko")] use crate::values::computed::TransitionProperty;
 use crate::values::computed::{ClipRect, Context};
 use crate::values::computed::ToComputedValue;
-use crate::values::computed::transform::Matrix3D;
 use crate::values::distance::{ComputeSquaredDistance, SquaredDistance};
 use crate::values::generics::effects::Filter;
 use void::{self, Void};
 
 /// Convert nsCSSPropertyID to TransitionProperty
 #[cfg(feature = "gecko")]
 #[allow(non_upper_case_globals)]
 impl From<nsCSSPropertyID> for TransitionProperty {
@@ -823,236 +820,16 @@ impl Animate for ClipRect {
     }
 }
 
 impl ToAnimatedZero for ClipRect {
     #[inline]
     fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
 }
 
-// We implement these methods for interpolation between two Matrix3D.
-// The interpolation code is in style/values/animated/transform.rs.
-impl Matrix3D {
-    /// Return true if this has 3D components.
-    pub fn is_3d(&self) -> bool {
-        self.m13 != 0.0 || self.m14 != 0.0 ||
-        self.m23 != 0.0 || self.m24 != 0.0 ||
-        self.m31 != 0.0 || self.m32 != 0.0 || self.m33 != 1.0 || self.m34 != 0.0 ||
-        self.m43 != 0.0 || self.m44 != 1.0
-    }
-
-    /// Return determinant value.
-    pub fn determinant(&self) -> CSSFloat {
-        self.m14 * self.m23 * self.m32 * self.m41 -
-        self.m13 * self.m24 * self.m32 * self.m41 -
-        self.m14 * self.m22 * self.m33 * self.m41 +
-        self.m12 * self.m24 * self.m33 * self.m41 +
-        self.m13 * self.m22 * self.m34 * self.m41 -
-        self.m12 * self.m23 * self.m34 * self.m41 -
-        self.m14 * self.m23 * self.m31 * self.m42 +
-        self.m13 * self.m24 * self.m31 * self.m42 +
-        self.m14 * self.m21 * self.m33 * self.m42 -
-        self.m11 * self.m24 * self.m33 * self.m42 -
-        self.m13 * self.m21 * self.m34 * self.m42 +
-        self.m11 * self.m23 * self.m34 * self.m42 +
-        self.m14 * self.m22 * self.m31 * self.m43 -
-        self.m12 * self.m24 * self.m31 * self.m43 -
-        self.m14 * self.m21 * self.m32 * self.m43 +
-        self.m11 * self.m24 * self.m32 * self.m43 +
-        self.m12 * self.m21 * self.m34 * self.m43 -
-        self.m11 * self.m22 * self.m34 * self.m43 -
-        self.m13 * self.m22 * self.m31 * self.m44 +
-        self.m12 * self.m23 * self.m31 * self.m44 +
-        self.m13 * self.m21 * self.m32 * self.m44 -
-        self.m11 * self.m23 * self.m32 * self.m44 -
-        self.m12 * self.m21 * self.m33 * self.m44 +
-        self.m11 * self.m22 * self.m33 * self.m44
-    }
-
-    /// Transpose a matrix.
-    pub fn transpose(&self) -> Self {
-        Self {
-            % for i in range(1, 5):
-            % for j in range(1, 5):
-            m${i}${j}: self.m${j}${i},
-            % endfor
-            % endfor
-        }
-    }
-
-    /// Return inverse matrix.
-    pub fn inverse(&self) -> Result<Matrix3D, ()> {
-        let mut det = self.determinant();
-
-        if det == 0.0 {
-            return Err(());
-        }
-
-        det = 1.0 / det;
-        let x = Matrix3D {
-            m11: det *
-            (self.m23*self.m34*self.m42 - self.m24*self.m33*self.m42 +
-             self.m24*self.m32*self.m43 - self.m22*self.m34*self.m43 -
-             self.m23*self.m32*self.m44 + self.m22*self.m33*self.m44),
-            m12: det *
-            (self.m14*self.m33*self.m42 - self.m13*self.m34*self.m42 -
-             self.m14*self.m32*self.m43 + self.m12*self.m34*self.m43 +
-             self.m13*self.m32*self.m44 - self.m12*self.m33*self.m44),
-            m13: det *
-            (self.m13*self.m24*self.m42 - self.m14*self.m23*self.m42 +
-             self.m14*self.m22*self.m43 - self.m12*self.m24*self.m43 -
-             self.m13*self.m22*self.m44 + self.m12*self.m23*self.m44),
-            m14: det *
-            (self.m14*self.m23*self.m32 - self.m13*self.m24*self.m32 -
-             self.m14*self.m22*self.m33 + self.m12*self.m24*self.m33 +
-             self.m13*self.m22*self.m34 - self.m12*self.m23*self.m34),
-            m21: det *
-            (self.m24*self.m33*self.m41 - self.m23*self.m34*self.m41 -
-             self.m24*self.m31*self.m43 + self.m21*self.m34*self.m43 +
-             self.m23*self.m31*self.m44 - self.m21*self.m33*self.m44),
-            m22: det *
-            (self.m13*self.m34*self.m41 - self.m14*self.m33*self.m41 +
-             self.m14*self.m31*self.m43 - self.m11*self.m34*self.m43 -
-             self.m13*self.m31*self.m44 + self.m11*self.m33*self.m44),
-            m23: det *
-            (self.m14*self.m23*self.m41 - self.m13*self.m24*self.m41 -
-             self.m14*self.m21*self.m43 + self.m11*self.m24*self.m43 +
-             self.m13*self.m21*self.m44 - self.m11*self.m23*self.m44),
-            m24: det *
-            (self.m13*self.m24*self.m31 - self.m14*self.m23*self.m31 +
-             self.m14*self.m21*self.m33 - self.m11*self.m24*self.m33 -
-             self.m13*self.m21*self.m34 + self.m11*self.m23*self.m34),
-            m31: det *
-            (self.m22*self.m34*self.m41 - self.m24*self.m32*self.m41 +
-             self.m24*self.m31*self.m42 - self.m21*self.m34*self.m42 -
-             self.m22*self.m31*self.m44 + self.m21*self.m32*self.m44),
-            m32: det *
-            (self.m14*self.m32*self.m41 - self.m12*self.m34*self.m41 -
-             self.m14*self.m31*self.m42 + self.m11*self.m34*self.m42 +
-             self.m12*self.m31*self.m44 - self.m11*self.m32*self.m44),
-            m33: det *
-            (self.m12*self.m24*self.m41 - self.m14*self.m22*self.m41 +
-             self.m14*self.m21*self.m42 - self.m11*self.m24*self.m42 -
-             self.m12*self.m21*self.m44 + self.m11*self.m22*self.m44),
-            m34: det *
-            (self.m14*self.m22*self.m31 - self.m12*self.m24*self.m31 -
-             self.m14*self.m21*self.m32 + self.m11*self.m24*self.m32 +
-             self.m12*self.m21*self.m34 - self.m11*self.m22*self.m34),
-            m41: det *
-            (self.m23*self.m32*self.m41 - self.m22*self.m33*self.m41 -
-             self.m23*self.m31*self.m42 + self.m21*self.m33*self.m42 +
-             self.m22*self.m31*self.m43 - self.m21*self.m32*self.m43),
-            m42: det *
-            (self.m12*self.m33*self.m41 - self.m13*self.m32*self.m41 +
-             self.m13*self.m31*self.m42 - self.m11*self.m33*self.m42 -
-             self.m12*self.m31*self.m43 + self.m11*self.m32*self.m43),
-            m43: det *
-            (self.m13*self.m22*self.m41 - self.m12*self.m23*self.m41 -
-             self.m13*self.m21*self.m42 + self.m11*self.m23*self.m42 +
-             self.m12*self.m21*self.m43 - self.m11*self.m22*self.m43),
-            m44: det *
-            (self.m12*self.m23*self.m31 - self.m13*self.m22*self.m31 +
-             self.m13*self.m21*self.m32 - self.m11*self.m23*self.m32 -
-             self.m12*self.m21*self.m33 + self.m11*self.m22*self.m33),
-        };
-
-        Ok(x)
-    }
-
-    /// Multiplies `pin * self`.
-    pub fn pre_mul_point4(&self, pin: &[f32; 4]) -> [f32; 4] {
-        [
-        % for i in range(1, 5):
-            pin[0] * self.m1${i} +
-            pin[1] * self.m2${i} +
-            pin[2] * self.m3${i} +
-            pin[3] * self.m4${i},
-        % endfor
-        ]
-    }
-
-    /// Multiplication of two 4x4 matrices.
-    pub fn multiply(&self, other: &Self) -> Self {
-        Matrix3D {
-        % for i in range(1, 5):
-            % for j in range(1, 5):
-                m${i}${j}:
-                    self.m${i}1 * other.m1${j} +
-                    self.m${i}2 * other.m2${j} +
-                    self.m${i}3 * other.m3${j} +
-                    self.m${i}4 * other.m4${j},
-            % endfor
-        % endfor
-        }
-    }
-
-    /// Scale the matrix by a factor.
-    #[inline]
-    pub fn scale_by_factor(&mut self, scaling_factor: CSSFloat) {
-        % for i in range(1, 5):
-        % for j in range(1, 5):
-            self.m${i}${j} *= scaling_factor;
-        % endfor
-        % endfor
-    }
-
-    /// This is used by retrieving the scale and shear factors
-    /// during decomposing a 3d matrix.
-    #[inline]
-    pub fn get_matrix_3x3_part(&self) -> [[f32; 3]; 3] {
-        let mut row: [[f32; 3]; 3] = [[0.0; 3]; 3];
-        % for i in range(1, 4):
-            row[${i - 1}][0] = self.m${i}1;
-            row[${i - 1}][1] = self.m${i}2;
-            row[${i - 1}][2] = self.m${i}3;
-        % endfor
-        row
-    }
-
-    /// Set perspective on the matrix.
-    #[inline]
-    pub fn set_perspective(&mut self, perspective: &Perspective) {
-        % for i in range(1, 5):
-            self.m${i}4 = perspective.${i - 1};
-        % endfor
-    }
-
-    /// Apply translate on the matrix.
-    #[inline]
-    pub fn apply_translate(&mut self, translate: &Translate3D) {
-        % for i in range(1, 5):
-        % for j in range(1, 4):
-            self.m4${i} += translate.${j - 1} * self.m${j}${i};
-        % endfor
-        % endfor
-    }
-
-    /// Apply scale on the matrix
-    #[inline]
-    pub fn apply_scale(&mut self, scale: &Scale3D) {
-        % for i in range(1, 4):
-        % for j in range(1, 5):
-            self.m${i}${j} *= scale.${i - 1};
-        % endfor
-        % endfor
-    }
-
-    /// Negate the matrix and the scaling factors.
-    /// This is a helper function for interpolation the Matrix.
-    #[inline]
-    pub fn negate_matrix_3x3_and_scaling_factor(row: &mut [[f32; 3]; 3], scale: &mut Scale3D) {
-        % for i in range(3):
-            scale.${i} *= -1.0;
-            row[${i}][0] *= -1.0;
-            row[${i}][1] *= -1.0;
-            row[${i}][2] *= -1.0;
-        % endfor
-    }
-}
-
 <%
     FILTER_FUNCTIONS = [ 'Blur', 'Brightness', 'Contrast', 'Grayscale',
                          'HueRotate', 'Invert', 'Opacity', 'Saturate',
                          'Sepia' ]
 %>
 
 /// <https://drafts.fxtf.org/filters/#animation-of-filters>
 impl Animate for AnimatedFilter {
--- a/servo/components/style/values/animated/transform.rs
+++ b/servo/components/style/values/animated/transform.rs
@@ -281,16 +281,25 @@ impl Animate for Matrix {
 #[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug)]
 pub struct Translate3D(pub f32, pub f32, pub f32);
 
 /// A 3d scale function.
 #[derive(Clone, ComputeSquaredDistance, Copy, Debug)]
 #[cfg_attr(feature = "servo", derive(MallocSizeOf))]
 pub struct Scale3D(pub f32, pub f32, pub f32);
 
+impl Scale3D {
+    /// Negate self.
+    fn negate(&mut self) {
+        self.0 *= -1.0;
+        self.1 *= -1.0;
+        self.2 *= -1.0;
+    }
+}
+
 impl Animate for Scale3D {
     fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
         Ok(Scale3D(
             animate_multiplicative_factor(self.0, other.0, procedure)?,
             animate_multiplicative_factor(self.1, other.1, procedure)?,
             animate_multiplicative_factor(self.2, other.2, procedure)?,
         ))
     }
@@ -637,17 +646,22 @@ fn decompose_3d_matrix(mut matrix: Matri
     row[2] = [row[2][0] / row2len, row[2][1] / row2len, row[2][2] / row2len];
     skew.1 /= scale.2;
     skew.2 /= scale.2;
 
     // At this point, the matrix (in rows) is orthonormal.
     // Check for a coordinate system flip.  If the determinant
     // is -1, then negate the matrix and the scaling factors.
     if dot(row[0], cross(row[1], row[2])) < 0.0 {
-        Matrix3D::negate_matrix_3x3_and_scaling_factor(&mut row, &mut scale);
+        scale.negate();
+        for i in 0..3 {
+            row[i][0] *= -1.0;
+            row[i][1] *= -1.0;
+            row[i][2] *= -1.0;
+        }
     }
 
     // Now, get the rotations out.
     let mut quaternion = Quaternion(
         0.5 * ((1.0 + row[0][0] - row[1][1] - row[2][2]).max(0.0) as f64).sqrt(),
         0.5 * ((1.0 - row[0][0] + row[1][1] - row[2][2]).max(0.0) as f64).sqrt(),
         0.5 * ((1.0 - row[0][0] - row[1][1] + row[2][2]).max(0.0) as f64).sqrt(),
         0.5 * ((1.0 + row[0][0] + row[1][1] + row[2][2]).max(0.0) as f64).sqrt()
--- a/servo/components/style/values/computed/transform.rs
+++ b/servo/components/style/values/computed/transform.rs
@@ -1,15 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Computed types for CSS values that are related to transformations.
 
 use super::CSSFloat;
+use crate::values::animated::transform::{Perspective, Scale3D, Translate3D};
 use crate::values::animated::ToAnimatedZero;
 use crate::values::computed::{Angle, Integer, Length, LengthOrPercentage, Number, Percentage};
 use crate::values::generics::transform as generic;
 use euclid::{Transform3D, Vector3D};
 use num_traits::Zero;
 
 pub use crate::values::generics::transform::TransformStyle;
 
@@ -42,42 +43,290 @@ pub type Matrix3D = generic::Matrix3D<Nu
 
 /// computed value of matrix()
 pub type Matrix = generic::Matrix<Number>;
 
 // we rustfmt_skip here because we want the matrices to look like
 // matrices instead of being split across lines
 #[cfg_attr(rustfmt, rustfmt_skip)]
 impl Matrix3D {
+    /// Get an identity matrix
     #[inline]
-    /// Get an identity matrix
     pub fn identity() -> Self {
         Self {
             m11: 1.0, m12: 0.0, m13: 0.0, m14: 0.0,
             m21: 0.0, m22: 1.0, m23: 0.0, m24: 0.0,
             m31: 0.0, m32: 0.0, m33: 1.0, m34: 0.0,
             m41: 0., m42: 0., m43: 0., m44: 1.0
         }
     }
 
     /// Convert to a 2D Matrix
+    #[inline]
     pub fn into_2d(self) -> Result<Matrix, ()> {
         if self.m13 == 0. && self.m23 == 0. &&
            self.m31 == 0. && self.m32 == 0. &&
            self.m33 == 1. && self.m34 == 0. &&
            self.m14 == 0. && self.m24 == 0. &&
            self.m43 == 0. && self.m44 == 1. {
             Ok(Matrix {
                 a: self.m11, c: self.m21, e: self.m41,
                 b: self.m12, d: self.m22, f: self.m42,
             })
         } else {
             Err(())
         }
     }
+
+    /// Return true if this has 3D components.
+    #[inline]
+    pub fn is_3d(&self) -> bool {
+        self.m13 != 0.0 || self.m14 != 0.0 ||
+        self.m23 != 0.0 || self.m24 != 0.0 ||
+        self.m31 != 0.0 || self.m32 != 0.0 ||
+        self.m33 != 1.0 || self.m34 != 0.0 ||
+        self.m43 != 0.0 || self.m44 != 1.0
+    }
+
+    /// Return determinant value.
+    #[inline]
+    pub fn determinant(&self) -> CSSFloat {
+        self.m14 * self.m23 * self.m32 * self.m41 -
+        self.m13 * self.m24 * self.m32 * self.m41 -
+        self.m14 * self.m22 * self.m33 * self.m41 +
+        self.m12 * self.m24 * self.m33 * self.m41 +
+        self.m13 * self.m22 * self.m34 * self.m41 -
+        self.m12 * self.m23 * self.m34 * self.m41 -
+        self.m14 * self.m23 * self.m31 * self.m42 +
+        self.m13 * self.m24 * self.m31 * self.m42 +
+        self.m14 * self.m21 * self.m33 * self.m42 -
+        self.m11 * self.m24 * self.m33 * self.m42 -
+        self.m13 * self.m21 * self.m34 * self.m42 +
+        self.m11 * self.m23 * self.m34 * self.m42 +
+        self.m14 * self.m22 * self.m31 * self.m43 -
+        self.m12 * self.m24 * self.m31 * self.m43 -
+        self.m14 * self.m21 * self.m32 * self.m43 +
+        self.m11 * self.m24 * self.m32 * self.m43 +
+        self.m12 * self.m21 * self.m34 * self.m43 -
+        self.m11 * self.m22 * self.m34 * self.m43 -
+        self.m13 * self.m22 * self.m31 * self.m44 +
+        self.m12 * self.m23 * self.m31 * self.m44 +
+        self.m13 * self.m21 * self.m32 * self.m44 -
+        self.m11 * self.m23 * self.m32 * self.m44 -
+        self.m12 * self.m21 * self.m33 * self.m44 +
+        self.m11 * self.m22 * self.m33 * self.m44
+    }
+
+    /// Transpose a matrix.
+    #[inline]
+    pub fn transpose(&self) -> Self {
+        Self {
+            m11: self.m11, m12: self.m21, m13: self.m31, m14: self.m41,
+            m21: self.m12, m22: self.m22, m23: self.m32, m24: self.m42,
+            m31: self.m13, m32: self.m23, m33: self.m33, m34: self.m43,
+            m41: self.m14, m42: self.m24, m43: self.m34, m44: self.m44,
+        }
+    }
+
+    /// Return inverse matrix.
+    pub fn inverse(&self) -> Result<Matrix3D, ()> {
+        let mut det = self.determinant();
+
+        if det == 0.0 {
+            return Err(());
+        }
+
+        det = 1.0 / det;
+        let x = Matrix3D {
+            m11: det *
+            (self.m23*self.m34*self.m42 - self.m24*self.m33*self.m42 +
+             self.m24*self.m32*self.m43 - self.m22*self.m34*self.m43 -
+             self.m23*self.m32*self.m44 + self.m22*self.m33*self.m44),
+            m12: det *
+            (self.m14*self.m33*self.m42 - self.m13*self.m34*self.m42 -
+             self.m14*self.m32*self.m43 + self.m12*self.m34*self.m43 +
+             self.m13*self.m32*self.m44 - self.m12*self.m33*self.m44),
+            m13: det *
+            (self.m13*self.m24*self.m42 - self.m14*self.m23*self.m42 +
+             self.m14*self.m22*self.m43 - self.m12*self.m24*self.m43 -
+             self.m13*self.m22*self.m44 + self.m12*self.m23*self.m44),
+            m14: det *
+            (self.m14*self.m23*self.m32 - self.m13*self.m24*self.m32 -
+             self.m14*self.m22*self.m33 + self.m12*self.m24*self.m33 +
+             self.m13*self.m22*self.m34 - self.m12*self.m23*self.m34),
+            m21: det *
+            (self.m24*self.m33*self.m41 - self.m23*self.m34*self.m41 -
+             self.m24*self.m31*self.m43 + self.m21*self.m34*self.m43 +
+             self.m23*self.m31*self.m44 - self.m21*self.m33*self.m44),
+            m22: det *
+            (self.m13*self.m34*self.m41 - self.m14*self.m33*self.m41 +
+             self.m14*self.m31*self.m43 - self.m11*self.m34*self.m43 -
+             self.m13*self.m31*self.m44 + self.m11*self.m33*self.m44),
+            m23: det *
+            (self.m14*self.m23*self.m41 - self.m13*self.m24*self.m41 -
+             self.m14*self.m21*self.m43 + self.m11*self.m24*self.m43 +
+             self.m13*self.m21*self.m44 - self.m11*self.m23*self.m44),
+            m24: det *
+            (self.m13*self.m24*self.m31 - self.m14*self.m23*self.m31 +
+             self.m14*self.m21*self.m33 - self.m11*self.m24*self.m33 -
+             self.m13*self.m21*self.m34 + self.m11*self.m23*self.m34),
+            m31: det *
+            (self.m22*self.m34*self.m41 - self.m24*self.m32*self.m41 +
+             self.m24*self.m31*self.m42 - self.m21*self.m34*self.m42 -
+             self.m22*self.m31*self.m44 + self.m21*self.m32*self.m44),
+            m32: det *
+            (self.m14*self.m32*self.m41 - self.m12*self.m34*self.m41 -
+             self.m14*self.m31*self.m42 + self.m11*self.m34*self.m42 +
+             self.m12*self.m31*self.m44 - self.m11*self.m32*self.m44),
+            m33: det *
+            (self.m12*self.m24*self.m41 - self.m14*self.m22*self.m41 +
+             self.m14*self.m21*self.m42 - self.m11*self.m24*self.m42 -
+             self.m12*self.m21*self.m44 + self.m11*self.m22*self.m44),
+            m34: det *
+            (self.m14*self.m22*self.m31 - self.m12*self.m24*self.m31 -
+             self.m14*self.m21*self.m32 + self.m11*self.m24*self.m32 +
+             self.m12*self.m21*self.m34 - self.m11*self.m22*self.m34),
+            m41: det *
+            (self.m23*self.m32*self.m41 - self.m22*self.m33*self.m41 -
+             self.m23*self.m31*self.m42 + self.m21*self.m33*self.m42 +
+             self.m22*self.m31*self.m43 - self.m21*self.m32*self.m43),
+            m42: det *
+            (self.m12*self.m33*self.m41 - self.m13*self.m32*self.m41 +
+             self.m13*self.m31*self.m42 - self.m11*self.m33*self.m42 -
+             self.m12*self.m31*self.m43 + self.m11*self.m32*self.m43),
+            m43: det *
+            (self.m13*self.m22*self.m41 - self.m12*self.m23*self.m41 -
+             self.m13*self.m21*self.m42 + self.m11*self.m23*self.m42 +
+             self.m12*self.m21*self.m43 - self.m11*self.m22*self.m43),
+            m44: det *
+            (self.m12*self.m23*self.m31 - self.m13*self.m22*self.m31 +
+             self.m13*self.m21*self.m32 - self.m11*self.m23*self.m32 -
+             self.m12*self.m21*self.m33 + self.m11*self.m22*self.m33),
+        };
+
+        Ok(x)
+    }
+
+    /// Multiply `pin * self`.
+    #[inline]
+    pub fn pre_mul_point4(&self, pin: &[f32; 4]) -> [f32; 4] {
+        [
+            pin[0] * self.m11 + pin[1] * self.m21 + pin[2] * self.m31 + pin[3] * self.m41,
+            pin[0] * self.m12 + pin[1] * self.m22 + pin[2] * self.m32 + pin[3] * self.m42,
+            pin[0] * self.m13 + pin[1] * self.m23 + pin[2] * self.m33 + pin[3] * self.m43,
+            pin[0] * self.m14 + pin[1] * self.m24 + pin[2] * self.m34 + pin[3] * self.m44,
+        ]
+    }
+
+    /// Return the multiplication of two 4x4 matrices.
+    #[inline]
+    pub fn multiply(&self, other: &Self) -> Self {
+        Matrix3D {
+            m11: self.m11 * other.m11 + self.m12 * other.m21 +
+                 self.m13 * other.m31 + self.m14 * other.m41,
+            m12: self.m11 * other.m12 + self.m12 * other.m22 +
+                 self.m13 * other.m32 + self.m14 * other.m42,
+            m13: self.m11 * other.m13 + self.m12 * other.m23 +
+                 self.m13 * other.m33 + self.m14 * other.m43,
+            m14: self.m11 * other.m14 + self.m12 * other.m24 +
+                 self.m13 * other.m34 + self.m14 * other.m44,
+            m21: self.m21 * other.m11 + self.m22 * other.m21 +
+                 self.m23 * other.m31 + self.m24 * other.m41,
+            m22: self.m21 * other.m12 + self.m22 * other.m22 +
+                 self.m23 * other.m32 + self.m24 * other.m42,
+            m23: self.m21 * other.m13 + self.m22 * other.m23 +
+                 self.m23 * other.m33 + self.m24 * other.m43,
+            m24: self.m21 * other.m14 + self.m22 * other.m24 +
+                 self.m23 * other.m34 + self.m24 * other.m44,
+            m31: self.m31 * other.m11 + self.m32 * other.m21 +
+                 self.m33 * other.m31 + self.m34 * other.m41,
+            m32: self.m31 * other.m12 + self.m32 * other.m22 +
+                 self.m33 * other.m32 + self.m34 * other.m42,
+            m33: self.m31 * other.m13 + self.m32 * other.m23 +
+                 self.m33 * other.m33 + self.m34 * other.m43,
+            m34: self.m31 * other.m14 + self.m32 * other.m24 +
+                 self.m33 * other.m34 + self.m34 * other.m44,
+            m41: self.m41 * other.m11 + self.m42 * other.m21 +
+                 self.m43 * other.m31 + self.m44 * other.m41,
+            m42: self.m41 * other.m12 + self.m42 * other.m22 +
+                 self.m43 * other.m32 + self.m44 * other.m42,
+            m43: self.m41 * other.m13 + self.m42 * other.m23 +
+                 self.m43 * other.m33 + self.m44 * other.m43,
+            m44: self.m41 * other.m14 + self.m42 * other.m24 +
+                 self.m43 * other.m34 + self.m44 * other.m44,
+        }
+    }
+
+    /// Scale the matrix by a factor.
+    #[inline]
+    pub fn scale_by_factor(&mut self, scaling_factor: CSSFloat) {
+        self.m11 *= scaling_factor;
+        self.m12 *= scaling_factor;
+        self.m13 *= scaling_factor;
+        self.m14 *= scaling_factor;
+        self.m21 *= scaling_factor;
+        self.m22 *= scaling_factor;
+        self.m23 *= scaling_factor;
+        self.m24 *= scaling_factor;
+        self.m31 *= scaling_factor;
+        self.m32 *= scaling_factor;
+        self.m33 *= scaling_factor;
+        self.m34 *= scaling_factor;
+        self.m41 *= scaling_factor;
+        self.m42 *= scaling_factor;
+        self.m43 *= scaling_factor;
+        self.m44 *= scaling_factor;
+    }
+
+    /// Return the matrix 3x3 part (top-left corner).
+    /// This is used by retrieving the scale and shear factors
+    /// during decomposing a 3d matrix.
+    #[inline]
+    pub fn get_matrix_3x3_part(&self) -> [[f32; 3]; 3] {
+        [
+            [ self.m11, self.m12, self.m13 ],
+            [ self.m21, self.m22, self.m23 ],
+            [ self.m31, self.m32, self.m33 ],
+        ]
+    }
+
+    /// Set perspective on the matrix.
+    #[inline]
+    pub fn set_perspective(&mut self, perspective: &Perspective) {
+        self.m14 = perspective.0;
+        self.m24 = perspective.1;
+        self.m34 = perspective.2;
+        self.m44 = perspective.3;
+    }
+
+    /// Apply translate on the matrix.
+    #[inline]
+    pub fn apply_translate(&mut self, translate: &Translate3D) {
+        self.m41 += translate.0 * self.m11 + translate.1 * self.m21 + translate.2 * self.m31;
+        self.m42 += translate.0 * self.m12 + translate.1 * self.m22 + translate.2 * self.m32;
+        self.m43 += translate.0 * self.m13 + translate.1 * self.m23 + translate.2 * self.m33;
+        self.m44 += translate.0 * self.m14 + translate.1 * self.m24 + translate.2 * self.m34;
+    }
+
+    /// Apply scale on the matrix.
+    #[inline]
+    pub fn apply_scale(&mut self, scale: &Scale3D) {
+        self.m11 *= scale.0;
+        self.m12 *= scale.0;
+        self.m13 *= scale.0;
+        self.m14 *= scale.0;
+        self.m21 *= scale.1;
+        self.m22 *= scale.1;
+        self.m23 *= scale.1;
+        self.m24 *= scale.1;
+        self.m31 *= scale.2;
+        self.m32 *= scale.2;
+        self.m33 *= scale.2;
+        self.m34 *= scale.2;
+    }
 }
 
 #[cfg_attr(rustfmt, rustfmt_skip)]
 impl Matrix {
     #[inline]
     /// Get an identity matrix
     pub fn identity() -> Self {
         Self {