LCOV - code coverage report
Current view: top level - gfx/2d - Matrix.h (source / functions) Hit Total Coverage
Test: output.info Lines: 561 864 64.9 %
Date: 2017-07-14 16:53:18 Functions: 162 242 66.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #ifndef MOZILLA_GFX_MATRIX_H_
       7             : #define MOZILLA_GFX_MATRIX_H_
       8             : 
       9             : #include "Types.h"
      10             : #include "Triangle.h"
      11             : #include "Rect.h"
      12             : #include "Point.h"
      13             : #include "Quaternion.h"
      14             : #include <iosfwd>
      15             : #include <math.h>
      16             : #include "mozilla/Attributes.h"
      17             : #include "mozilla/DebugOnly.h"
      18             : #include "mozilla/FloatingPoint.h"
      19             : 
      20             : namespace mozilla {
      21             : namespace gfx {
      22             : 
      23       27832 : static inline bool FuzzyEqual(Float aV1, Float aV2) {
      24             :   // XXX - Check if fabs does the smart thing and just negates the sign bit.
      25       27832 :   return fabs(aV2 - aV1) < 1e-6;
      26             : }
      27             : 
      28             : template<class T>
      29             : class BaseMatrix
      30             : {
      31             :   // Alias that maps to either Point or PointDouble depending on whether T is a
      32             :   // float or a double.
      33             :   typedef PointTyped<UnknownUnits, T> MatrixPoint;
      34             :   // Same for size and rect
      35             :   typedef SizeTyped<UnknownUnits, T> MatrixSize;
      36             :   typedef RectTyped<UnknownUnits, T> MatrixRect;
      37             : 
      38             : public:
      39       10322 :   BaseMatrix()
      40             :     : _11(1.0f), _12(0)
      41             :     , _21(0), _22(1.0f)
      42       10322 :     , _31(0), _32(0)
      43       10322 :   {}
      44        6734 :   BaseMatrix(T a11, T a12, T a21, T a22, T a31, T a32)
      45             :     : _11(a11), _12(a12)
      46             :     , _21(a21), _22(a22)
      47        6734 :     , _31(a31), _32(a32)
      48        6734 :   {}
      49             :   union {
      50             :     struct {
      51             :       T _11, _12;
      52             :       T _21, _22;
      53             :       T _31, _32;
      54             :     };
      55             :     T components[6];
      56             :   };
      57             : 
      58          25 :   MOZ_ALWAYS_INLINE BaseMatrix Copy() const
      59             :   {
      60          25 :     return BaseMatrix<T>(*this);
      61             :   }
      62             : 
      63             :   friend std::ostream& operator<<(std::ostream& aStream, const BaseMatrix& aMatrix)
      64             :   {
      65             :     return aStream << "[ " << aMatrix._11
      66             :                    << " "  << aMatrix._12
      67             :                    << "; " << aMatrix._21
      68             :                    << " "  << aMatrix._22
      69             :                    << "; " << aMatrix._31
      70             :                    << " "  << aMatrix._32
      71             :                    << "; ]";
      72             :   }
      73             : 
      74       10972 :   MatrixPoint TransformPoint(const MatrixPoint &aPoint) const
      75             :   {
      76       10972 :     MatrixPoint retPoint;
      77             : 
      78       10972 :     retPoint.x = aPoint.x * _11 + aPoint.y * _21 + _31;
      79       10972 :     retPoint.y = aPoint.x * _12 + aPoint.y * _22 + _32;
      80             : 
      81       10972 :     return retPoint;
      82             :   }
      83             : 
      84        1111 :   MatrixSize TransformSize(const MatrixSize &aSize) const
      85             :   {
      86        1111 :     MatrixSize retSize;
      87             : 
      88        1111 :     retSize.width = aSize.width * _11 + aSize.height * _21;
      89        1111 :     retSize.height = aSize.width * _12 + aSize.height * _22;
      90             : 
      91        1111 :     return retSize;
      92             :   }
      93             : 
      94             :   /**
      95             :    * In most cases you probably want to use TransformBounds. This function
      96             :    * just transforms the top-left and size separately and constructs a rect
      97             :    * from those results.
      98             :    */
      99         216 :   MatrixRect TransformRect(const MatrixRect& aRect) const
     100             :   {
     101         432 :     return MatrixRect(TransformPoint(aRect.TopLeft()),
     102         648 :                       TransformSize(aRect.Size()));
     103             :   }
     104             : 
     105        2111 :   GFX2D_API MatrixRect TransformBounds(const MatrixRect& aRect) const
     106             :   {
     107             :     int i;
     108        2111 :     MatrixPoint quad[4];
     109             :     T min_x, max_x;
     110             :     T min_y, max_y;
     111             : 
     112        2111 :     quad[0] = TransformPoint(aRect.TopLeft());
     113        2111 :     quad[1] = TransformPoint(aRect.TopRight());
     114        2111 :     quad[2] = TransformPoint(aRect.BottomLeft());
     115        2111 :     quad[3] = TransformPoint(aRect.BottomRight());
     116             : 
     117        2111 :     min_x = max_x = quad[0].x;
     118        2111 :     min_y = max_y = quad[0].y;
     119             : 
     120        8444 :     for (i = 1; i < 4; i++) {
     121        6333 :       if (quad[i].x < min_x)
     122           0 :         min_x = quad[i].x;
     123        6333 :       if (quad[i].x > max_x)
     124        2111 :         max_x = quad[i].x;
     125             : 
     126        6333 :       if (quad[i].y < min_y)
     127           0 :         min_y = quad[i].y;
     128        6333 :       if (quad[i].y > max_y)
     129        2111 :         max_y = quad[i].y;
     130             :     }
     131             : 
     132        2111 :     return MatrixRect(min_x, min_y, max_x - min_x, max_y - min_y);
     133             :   }
     134             : 
     135         466 :   static BaseMatrix<T> Translation(T aX, T aY)
     136             :   {
     137         466 :     return BaseMatrix<T>(1.0f, 0.0f, 0.0f, 1.0f, aX, aY);
     138             :   }
     139             : 
     140          86 :   static BaseMatrix<T> Translation(MatrixPoint aPoint)
     141             :   {
     142          86 :     return Translation(aPoint.x, aPoint.y);
     143             :   }
     144             : 
     145             :   /**
     146             :    * Apply a translation to this matrix.
     147             :    *
     148             :    * The "Pre" in this method's name means that the translation is applied
     149             :    * -before- this matrix's existing transformation. That is, any vector that
     150             :    * is multiplied by the resulting matrix will first be translated, then be
     151             :    * transformed by the original transform.
     152             :    *
     153             :    * Calling this method will result in this matrix having the same value as
     154             :    * the result of:
     155             :    *
     156             :    *   BaseMatrix<T>::Translation(x, y) * this
     157             :    *
     158             :    * (Note that in performance critical code multiplying by the result of a
     159             :    * Translation()/Scaling() call is not recommended since that results in a
     160             :    * full matrix multiply involving 12 floating-point multiplications. Calling
     161             :    * this method would be preferred since it only involves four floating-point
     162             :    * multiplications.)
     163             :    */
     164         281 :   BaseMatrix<T> &PreTranslate(T aX, T aY)
     165             :   {
     166         281 :     _31 += _11 * aX + _21 * aY;
     167         281 :     _32 += _12 * aX + _22 * aY;
     168             : 
     169         281 :     return *this;
     170             :   }
     171             : 
     172         235 :   BaseMatrix<T> &PreTranslate(const MatrixPoint &aPoint)
     173             :   {
     174         235 :     return PreTranslate(aPoint.x, aPoint.y);
     175             :   }
     176             : 
     177             :   /**
     178             :    * Similar to PreTranslate, but the translation is applied -after- this
     179             :    * matrix's existing transformation instead of before it.
     180             :    *
     181             :    * This method is generally less used than PreTranslate since typically code
     182             :    * want to adjust an existing user space to device space matrix to create a
     183             :    * transform to device space from a -new- user space (translated from the
     184             :    * previous user space). In that case consumers will need to use the Pre*
     185             :    * variants of the matrix methods rather than using the Post* methods, since
     186             :    * the Post* methods add a transform to the device space end of the
     187             :    * transformation.
     188             :    */
     189         930 :   BaseMatrix<T> &PostTranslate(T aX, T aY)
     190             :   {
     191         930 :     _31 += aX;
     192         930 :     _32 += aY;
     193         930 :     return *this;
     194             :   }
     195             : 
     196          27 :   BaseMatrix<T> &PostTranslate(const MatrixPoint &aPoint)
     197             :   {
     198          27 :     return PostTranslate(aPoint.x, aPoint.y);
     199             :   }
     200             : 
     201          72 :   static BaseMatrix<T> Scaling(T aScaleX, T aScaleY)
     202             :   {
     203          72 :     return BaseMatrix<T>(aScaleX, 0.0f, 0.0f, aScaleY, 0.0f, 0.0f);
     204             :   }
     205             :   
     206             :   /**
     207             :    * Similar to PreTranslate, but applies a scale instead of a translation.
     208             :    */
     209         166 :   BaseMatrix<T> &PreScale(T aX, T aY)
     210             :   {
     211         166 :     _11 *= aX;
     212         166 :     _12 *= aX;
     213         166 :     _21 *= aY;
     214         166 :     _22 *= aY;
     215             : 
     216         166 :     return *this;
     217             :   }
     218             : 
     219             :   /**
     220             :    * Similar to PostTranslate, but applies a scale instead of a translation.
     221             :    */
     222         770 :   BaseMatrix<T> &PostScale(T aScaleX, T aScaleY)
     223             :   {
     224         770 :     _11 *= aScaleX;
     225         770 :     _12 *= aScaleY;
     226         770 :     _21 *= aScaleX;
     227         770 :     _22 *= aScaleY;
     228         770 :     _31 *= aScaleX;
     229         770 :     _32 *= aScaleY;
     230             : 
     231         770 :     return *this;
     232             :   }
     233             : 
     234             :   GFX2D_API static BaseMatrix<T> Rotation(T aAngle);
     235             : 
     236             :   /**
     237             :    * Similar to PreTranslate, but applies a rotation instead of a translation.
     238             :    */
     239           0 :   BaseMatrix<T> &PreRotate(T aAngle)
     240             :   {
     241           0 :     return *this = BaseMatrix<T>::Rotation(aAngle) * *this;
     242             :   }
     243             : 
     244        1601 :   bool Invert()
     245             :   {
     246             :     // Compute co-factors.
     247        1601 :     T A = _22;
     248        1601 :     T B = -_21;
     249        1601 :     T C = _21 * _32 - _22 * _31;
     250        1601 :     T D = -_12;
     251        1601 :     T E = _11;
     252        1601 :     T F = _31 * _12 - _11 * _32;
     253             : 
     254        1601 :     T det = Determinant();
     255             : 
     256        1601 :     if (!det) {
     257           0 :       return false;
     258             :     }
     259             : 
     260        1601 :     T inv_det = 1 / det;
     261             : 
     262        1601 :     _11 = inv_det * A;
     263        1601 :     _12 = inv_det * D;
     264        1601 :     _21 = inv_det * B;
     265        1601 :     _22 = inv_det * E;
     266        1601 :     _31 = inv_det * C;
     267        1601 :     _32 = inv_det * F;
     268             : 
     269        1601 :     return true;
     270             :   }
     271             : 
     272          36 :   BaseMatrix<T> Inverse() const
     273             :   {
     274          36 :     BaseMatrix<T> clone = *this;
     275          72 :     DebugOnly<bool> inverted = clone.Invert();
     276          36 :     MOZ_ASSERT(inverted, "Attempted to get the inverse of a non-invertible matrix");
     277          72 :     return clone;
     278             :   }
     279             : 
     280        2650 :   T Determinant() const
     281             :   {
     282        2650 :     return _11 * _22 - _12 * _21;
     283             :   }
     284             : 
     285        1916 :   BaseMatrix<T> operator*(const BaseMatrix<T> &aMatrix) const
     286             :   {
     287        1916 :     BaseMatrix<T> resultMatrix;
     288             : 
     289        1916 :     resultMatrix._11 = this->_11 * aMatrix._11 + this->_12 * aMatrix._21;
     290        1916 :     resultMatrix._12 = this->_11 * aMatrix._12 + this->_12 * aMatrix._22;
     291        1916 :     resultMatrix._21 = this->_21 * aMatrix._11 + this->_22 * aMatrix._21;
     292        1916 :     resultMatrix._22 = this->_21 * aMatrix._12 + this->_22 * aMatrix._22;
     293        1916 :     resultMatrix._31 = this->_31 * aMatrix._11 + this->_32 * aMatrix._21 + aMatrix._31;
     294        1916 :     resultMatrix._32 = this->_31 * aMatrix._12 + this->_32 * aMatrix._22 + aMatrix._32;
     295             : 
     296        1916 :     return resultMatrix;
     297             :   }
     298             : 
     299         124 :   BaseMatrix<T>& operator*=(const BaseMatrix<T> &aMatrix)
     300             :   {
     301         124 :     *this = *this * aMatrix;
     302         124 :     return *this;
     303             :   }
     304             : 
     305             :   /**
     306             :    * Multiplies *this with aMatrix and returns the result.
     307             :    */
     308             :   Matrix4x4 operator*(const Matrix4x4& aMatrix) const;
     309             : 
     310             :   /**
     311             :    * Multiplies in the opposite order to operator=*.
     312             :    */
     313          96 :   BaseMatrix<T> &PreMultiply(const BaseMatrix<T> &aMatrix)
     314             :   {
     315          96 :     *this = aMatrix * *this;
     316          96 :     return *this;
     317             :   }
     318             : 
     319             :   /* Returns true if the other matrix is fuzzy-equal to this matrix.
     320             :    * Note that this isn't a cheap comparison!
     321             :    */
     322           0 :   bool operator==(const BaseMatrix<T>& other) const
     323             :   {
     324           0 :     return FuzzyEqual(_11, other._11) && FuzzyEqual(_12, other._12) &&
     325           0 :            FuzzyEqual(_21, other._21) && FuzzyEqual(_22, other._22) &&
     326           0 :            FuzzyEqual(_31, other._31) && FuzzyEqual(_32, other._32);
     327             :   }
     328             : 
     329           0 :   bool operator!=(const BaseMatrix<T>& other) const
     330             :   {
     331           0 :     return !(*this == other);
     332             :   }
     333             : 
     334           0 :   bool ExactlyEquals(const BaseMatrix<T>& o) const
     335             :   {
     336           0 :     return _11 == o._11 && _12 == o._12 &&
     337           0 :            _21 == o._21 && _22 == o._22 &&
     338           0 :            _31 == o._31 && _32 == o._32;
     339             :   }
     340             : 
     341             :   /* Verifies that the matrix contains no Infs or NaNs. */
     342           0 :   bool IsFinite() const
     343             :   {
     344           0 :     return mozilla::IsFinite(_11) && mozilla::IsFinite(_12) &&
     345           0 :            mozilla::IsFinite(_21) && mozilla::IsFinite(_22) &&
     346           0 :            mozilla::IsFinite(_31) && mozilla::IsFinite(_32);
     347             :   }
     348             : 
     349             :   /* Returns true if the matrix is a rectilinear transformation (i.e.
     350             :    * grid-aligned rectangles are transformed to grid-aligned rectangles)
     351             :    */
     352         907 :   bool IsRectilinear() const {
     353         907 :     if (FuzzyEqual(_12, 0) && FuzzyEqual(_21, 0)) {
     354         907 :       return true;
     355           0 :     } else if (FuzzyEqual(_22, 0) && FuzzyEqual(_11, 0)) {
     356           0 :       return true;
     357             :     }
     358             : 
     359           0 :     return false;
     360             :   }
     361             : 
     362             :   /**
     363             :    * Returns true if the matrix is anything other than a straight
     364             :    * translation by integers.
     365             :   */
     366        1336 :   bool HasNonIntegerTranslation() const {
     367        2669 :     return HasNonTranslation() ||
     368        2669 :       !FuzzyEqual(_31, floor(_31 + T(0.5))) ||
     369        2669 :       !FuzzyEqual(_32, floor(_32 + T(0.5)));
     370             :   }
     371             : 
     372             :   /**
     373             :    * Returns true if the matrix only has an integer translation.
     374             :    */
     375             :   bool HasOnlyIntegerTranslation() const {
     376             :     return !HasNonIntegerTranslation();
     377             :   }
     378             : 
     379             :   /**
     380             :    * Returns true if the matrix has any transform other
     381             :    * than a straight translation.
     382             :    */
     383        1772 :   bool HasNonTranslation() const {
     384        5076 :     return !FuzzyEqual(_11, 1.0) || !FuzzyEqual(_22, 1.0) ||
     385        5076 :            !FuzzyEqual(_12, 0.0) || !FuzzyEqual(_21, 0.0);
     386             :   }
     387             : 
     388             :   /**
     389             :    * Returns true if the matrix has any transform other
     390             :    * than a translation or a -1 y scale (y axis flip)
     391             :    */
     392           0 :   bool HasNonTranslationOrFlip() const {
     393           0 :       return !FuzzyEqual(_11, 1.0) ||
     394           0 :              (!FuzzyEqual(_22, 1.0) && !FuzzyEqual(_22, -1.0)) ||
     395           0 :              !FuzzyEqual(_21, 0.0) || !FuzzyEqual(_12, 0.0);
     396             :   }
     397             : 
     398             :   /* Returns true if the matrix is an identity matrix.
     399             :    */
     400        1062 :   bool IsIdentity() const
     401             :   {
     402        1704 :     return _11 == 1.0f && _12 == 0.0f &&
     403         963 :            _21 == 0.0f && _22 == 1.0f &&
     404        1693 :            _31 == 0.0f && _32 == 0.0f;
     405             :   }
     406             : 
     407             :   /* Returns true if the matrix is singular.
     408             :    */
     409         154 :   bool IsSingular() const
     410             :   {
     411         154 :     T det = Determinant();
     412         154 :     return !mozilla::IsFinite(det) || det == 0;
     413             :   }
     414             : 
     415          93 :   GFX2D_API BaseMatrix<T>& NudgeToIntegers()
     416             :   {
     417          93 :     NudgeToInteger(&_11);
     418          93 :     NudgeToInteger(&_12);
     419          93 :     NudgeToInteger(&_21);
     420          93 :     NudgeToInteger(&_22);
     421          93 :     NudgeToInteger(&_31);
     422          93 :     NudgeToInteger(&_32);
     423          93 :     return *this;
     424             :   }
     425             : 
     426         311 :   bool IsTranslation() const
     427             :   {
     428         933 :     return FuzzyEqual(_11, 1.0f) && FuzzyEqual(_12, 0.0f) &&
     429         933 :            FuzzyEqual(_21, 0.0f) && FuzzyEqual(_22, 1.0f);
     430             :   }
     431             : 
     432         290 :   static bool FuzzyIsInteger(T aValue)
     433             :   {
     434         290 :     return FuzzyEqual(aValue, floorf(aValue + 0.5f));
     435             :   }
     436             : 
     437         145 :   bool IsIntegerTranslation() const
     438             :   {
     439         145 :     return IsTranslation() && FuzzyIsInteger(_31) && FuzzyIsInteger(_32);
     440             :   }
     441             : 
     442             :   bool IsAllIntegers() const
     443             :   {
     444             :     return FuzzyIsInteger(_11) && FuzzyIsInteger(_12) &&
     445             :            FuzzyIsInteger(_21) && FuzzyIsInteger(_22) &&
     446             :            FuzzyIsInteger(_31) && FuzzyIsInteger(_32);
     447             :   }
     448             : 
     449         779 :   MatrixPoint GetTranslation() const {
     450         779 :     return MatrixPoint(_31, _32);
     451             :   }
     452             : 
     453             :   /**
     454             :    * Returns true if matrix is multiple of 90 degrees rotation with flipping,
     455             :    * scaling and translation.
     456             :    */
     457         150 :   bool PreservesAxisAlignedRectangles() const {
     458         150 :       return ((FuzzyEqual(_11, 0.0) && FuzzyEqual(_22, 0.0))
     459         300 :           || (FuzzyEqual(_12, 0.0) && FuzzyEqual(_21, 0.0)));
     460             :   }
     461             : 
     462             :   /**
     463             :    * Returns true if the matrix has any transform other
     464             :    * than a translation or scale; this is, if there is
     465             :    * rotation.
     466             :    */
     467         523 :   bool HasNonAxisAlignedTransform() const {
     468         523 :       return !FuzzyEqual(_21, 0.0) || !FuzzyEqual(_12, 0.0);
     469             :   }
     470             : 
     471             :   /**
     472             :    * Returns true if the matrix has negative scaling (i.e. flip).
     473             :    */
     474         176 :   bool HasNegativeScaling() const {
     475         176 :       return (_11 < 0.0) || (_22 < 0.0);
     476             :   }
     477             : 
     478             :   /**
     479             :    * Computes the scale factors of this matrix; that is,
     480             :    * the amounts each basis vector is scaled by.
     481             :    * The xMajor parameter indicates if the larger scale is
     482             :    * to be assumed to be in the X direction or not.
     483             :    */
     484         895 :   MatrixSize ScaleFactors(bool xMajor) const {
     485         895 :     T det = Determinant();
     486             : 
     487         895 :     if (det == 0.0) {
     488           0 :       return MatrixSize(0.0, 0.0);
     489             :     }
     490             : 
     491         895 :     MatrixSize sz = xMajor ? MatrixSize(1.0, 0.0) : MatrixSize(0.0, 1.0);
     492         895 :     sz = TransformSize(sz);
     493             : 
     494         895 :     T major = sqrt(sz.width * sz.width + sz.height * sz.height);
     495         895 :     T minor = 0.0;
     496             : 
     497             :     // ignore mirroring
     498         895 :     if (det < 0.0) {
     499           0 :       det = - det;
     500             :     }
     501             : 
     502         895 :     if (major) {
     503         895 :       minor = det / major;
     504             :     }
     505             : 
     506         895 :     if (xMajor) {
     507         895 :       return MatrixSize(major, minor);
     508             :     }
     509             : 
     510           0 :     return MatrixSize(minor, major);
     511             :   }
     512             : };
     513             : 
     514             : typedef BaseMatrix<Float> Matrix;
     515             : typedef BaseMatrix<Double> MatrixDouble;
     516             : 
     517             : // Helper functions used by Matrix4x4Typed defined in Matrix.cpp
     518             : double
     519             : SafeTangent(double aTheta);
     520             : double
     521             : FlushToZero(double aVal);
     522             : 
     523             : template<class Units, class F>
     524             : Point4DTyped<Units, F>
     525           0 : ComputePerspectivePlaneIntercept(const Point4DTyped<Units, F>& aFirst,
     526             :                                  const Point4DTyped<Units, F>& aSecond)
     527             : {
     528             :   // This function will always return a point with a w value of 0.
     529             :   // The X, Y, and Z components will point towards an infinite vanishing
     530             :   // point.
     531             : 
     532             :   // We want to interpolate aFirst and aSecond to find the point intersecting
     533             :   // with the w=0 plane.
     534             : 
     535             :   // Since we know what we want the w component to be, we can rearrange the
     536             :   // interpolation equation and solve for t.
     537           0 :   float t = -aFirst.w / (aSecond.w - aFirst.w);
     538             : 
     539             :   // Use t to find the remainder of the components
     540           0 :   return aFirst + (aSecond - aFirst) * t;
     541             : }
     542             : 
     543             : 
     544             : template <typename SourceUnits, typename TargetUnits>
     545             : class Matrix4x4Typed
     546             : {
     547             : public:
     548             :   typedef PointTyped<SourceUnits> SourcePoint;
     549             :   typedef PointTyped<TargetUnits> TargetPoint;
     550             :   typedef Point3DTyped<SourceUnits> SourcePoint3D;
     551             :   typedef Point3DTyped<TargetUnits> TargetPoint3D;
     552             :   typedef Point4DTyped<SourceUnits> SourcePoint4D;
     553             :   typedef Point4DTyped<TargetUnits> TargetPoint4D;
     554             :   typedef RectTyped<SourceUnits> SourceRect;
     555             :   typedef RectTyped<TargetUnits> TargetRect;
     556             : 
     557        6918 :   Matrix4x4Typed()
     558             :     : _11(1.0f), _12(0.0f), _13(0.0f), _14(0.0f)
     559             :     , _21(0.0f), _22(1.0f), _23(0.0f), _24(0.0f)
     560             :     , _31(0.0f), _32(0.0f), _33(1.0f), _34(0.0f)
     561        6918 :     , _41(0.0f), _42(0.0f), _43(0.0f), _44(1.0f)
     562        6918 :   {}
     563             : 
     564        2759 :   Matrix4x4Typed(Float a11, Float a12, Float a13, Float a14,
     565             :                  Float a21, Float a22, Float a23, Float a24,
     566             :                  Float a31, Float a32, Float a33, Float a34,
     567             :                  Float a41, Float a42, Float a43, Float a44)
     568             :     : _11(a11), _12(a12), _13(a13), _14(a14)
     569             :     , _21(a21), _22(a22), _23(a23), _24(a24)
     570             :     , _31(a31), _32(a32), _33(a33), _34(a34)
     571        2759 :     , _41(a41), _42(a42), _43(a43), _44(a44)
     572        2759 :   {}
     573             : 
     574           0 :   explicit Matrix4x4Typed(const Float aArray[16])
     575             :   {
     576           0 :     memcpy(components, aArray, sizeof(components));
     577           0 :   }
     578             : 
     579        5436 :   Matrix4x4Typed(const Matrix4x4Typed& aOther)
     580             :   {
     581        5436 :     memcpy(this, &aOther, sizeof(*this));
     582        5436 :   }
     583             : 
     584             :   union {
     585             :     struct {
     586             :       Float _11, _12, _13, _14;
     587             :       Float _21, _22, _23, _24;
     588             :       Float _31, _32, _33, _34;
     589             :       Float _41, _42, _43, _44;
     590             :     };
     591             :     Float components[16];
     592             :   };
     593             : 
     594             :   friend std::ostream& operator<<(std::ostream& aStream, const Matrix4x4Typed& aMatrix)
     595             :   {
     596             :     const Float *f = &aMatrix._11;
     597             :     aStream << "[ " << f[0] << " "  << f[1] << " " << f[2] << " " << f[3] << " ;" << std::endl; f += 4;
     598             :     aStream << "  " << f[0] << " "  << f[1] << " " << f[2] << " " << f[3] << " ;" << std::endl; f += 4;
     599             :     aStream << "  " << f[0] << " "  << f[1] << " " << f[2] << " " << f[3] << " ;" << std::endl; f += 4;
     600             :     aStream << "  " << f[0] << " "  << f[1] << " " << f[2] << " " << f[3] << " ]" << std::endl;
     601             :     return aStream;
     602             :   }
     603             : 
     604           0 :   Point4D& operator[](int aIndex)
     605             :   {
     606           0 :       MOZ_ASSERT(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index");
     607           0 :       return *reinterpret_cast<Point4D*>((&_11)+4*aIndex);
     608             :   }
     609           0 :   const Point4D& operator[](int aIndex) const
     610             :   {
     611           0 :       MOZ_ASSERT(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index");
     612           0 :       return *reinterpret_cast<const Point4D*>((&_11)+4*aIndex);
     613             :   }
     614             : 
     615             :   /**
     616             :    * Returns true if the matrix is isomorphic to a 2D affine transformation.
     617             :    */
     618        1775 :   bool Is2D() const
     619             :   {
     620        3550 :     if (_13 != 0.0f || _14 != 0.0f ||
     621        5325 :         _23 != 0.0f || _24 != 0.0f ||
     622        5325 :         _31 != 0.0f || _32 != 0.0f || _33 != 1.0f || _34 != 0.0f ||
     623        3550 :         _43 != 0.0f || _44 != 1.0f) {
     624           0 :       return false;
     625             :     }
     626        1775 :     return true;
     627             :   }
     628             : 
     629        1148 :   bool Is2D(Matrix* aMatrix) const {
     630        1148 :     if (!Is2D()) {
     631           0 :       return false;
     632             :     }
     633        1148 :     if (aMatrix) {
     634        1148 :       aMatrix->_11 = _11;
     635        1148 :       aMatrix->_12 = _12;
     636        1148 :       aMatrix->_21 = _21;
     637        1148 :       aMatrix->_22 = _22;
     638        1148 :       aMatrix->_31 = _41;
     639        1148 :       aMatrix->_32 = _42;
     640             :     }
     641        1148 :     return true;
     642             :   }
     643             : 
     644         176 :   Matrix As2D() const
     645             :   {
     646         176 :     MOZ_ASSERT(Is2D(), "Matrix is not a 2D affine transform");
     647             : 
     648         176 :     return Matrix(_11, _12, _21, _22, _41, _42);
     649             :   }
     650             : 
     651        1348 :   bool CanDraw2D(Matrix* aMatrix = nullptr) const {
     652        2696 :     if (_14 != 0.0f ||
     653        2696 :         _24 != 0.0f ||
     654        1348 :         _44 != 1.0f) {
     655           0 :       return false;
     656             :     }
     657        1348 :     if (aMatrix) {
     658        1131 :       aMatrix->_11 = _11;
     659        1131 :       aMatrix->_12 = _12;
     660        1131 :       aMatrix->_21 = _21;
     661        1131 :       aMatrix->_22 = _22;
     662        1131 :       aMatrix->_31 = _41;
     663        1131 :       aMatrix->_32 = _42;
     664             :     }
     665        1348 :     return true;
     666             :   }
     667             : 
     668         569 :   Matrix4x4Typed& ProjectTo2D() {
     669         569 :     _31 = 0.0f;
     670         569 :     _32 = 0.0f;
     671         569 :     _13 = 0.0f;
     672         569 :     _23 = 0.0f;
     673         569 :     _33 = 1.0f;
     674         569 :     _43 = 0.0f;
     675         569 :     _34 = 0.0f;
     676             :     // Some matrices, such as those derived from perspective transforms,
     677             :     // can modify _44 from 1, while leaving the rest of the fourth column
     678             :     // (_14, _24) at 0. In this case, after resetting the third row and
     679             :     // third column above, the value of _44 functions only to scale the
     680             :     // coordinate transform divide by W. The matrix can be converted to
     681             :     // a true 2D matrix by normalizing out the scaling effect of _44 on
     682             :     // the remaining components ahead of time.
     683        1138 :     if (_14 == 0.0f && _24 == 0.0f &&
     684         569 :         _44 != 1.0f && _44 != 0.0f) {
     685           0 :       Float scale = 1.0f / _44;
     686           0 :       _11 *= scale;
     687           0 :       _12 *= scale;
     688           0 :       _21 *= scale;
     689           0 :       _22 *= scale;
     690           0 :       _41 *= scale;
     691           0 :       _42 *= scale;
     692           0 :       _44 = 1.0f;
     693             :     }
     694         569 :     return *this;
     695             :   }
     696             : 
     697             :   template<class F>
     698             :   Point4DTyped<TargetUnits, F>
     699         597 :   ProjectPoint(const PointTyped<SourceUnits, F>& aPoint) const {
     700             :     // Find a value for z that will transform to 0.
     701             : 
     702             :     // The transformed value of z is computed as:
     703             :     // z' = aPoint.x * _13 + aPoint.y * _23 + z * _33 + _43;
     704             : 
     705             :     // Solving for z when z' = 0 gives us:
     706         597 :     F z = -(aPoint.x * _13 + aPoint.y * _23 + _43) / _33;
     707             : 
     708             :     // Compute the transformed point
     709         597 :     return this->TransformPoint(Point4DTyped<SourceUnits, F>(aPoint.x, aPoint.y, z, 1));
     710             :   }
     711             : 
     712             :   template<class F>
     713             :   RectTyped<TargetUnits, F>
     714         143 :   ProjectRectBounds(const RectTyped<SourceUnits, F>& aRect, const RectTyped<TargetUnits, F>& aClip) const
     715             :   {
     716             :     // This function must never return std::numeric_limits<Float>::max() or any
     717             :     // other arbitrary large value in place of inifinity.  This often occurs when
     718             :     // aRect is an inversed projection matrix or when aRect is transformed to be
     719             :     // partly behind and in front of the camera (w=0 plane in homogenous
     720             :     // coordinates) - See Bug 1035611
     721             : 
     722             :     // Some call-sites will call RoundGfxRectToAppRect which clips both the
     723             :     // extents and dimensions of the rect to be bounded by nscoord_MAX.
     724             :     // If we return a Rect that, when converted to nscoords, has a width or height
     725             :     // greater than nscoord_MAX, RoundGfxRectToAppRect will clip the overflow
     726             :     // off both the min and max end of the rect after clipping the extents of the
     727             :     // rect, resulting in a translation of the rect towards the infinite end.
     728             : 
     729             :     // The bounds returned by ProjectRectBounds are expected to be clipped only on
     730             :     // the edges beyond the bounds of the coordinate system; otherwise, the
     731             :     // clipped bounding box would be smaller than the correct one and result
     732             :     // bugs such as incorrect culling (eg. Bug 1073056)
     733             : 
     734             :     // To address this without requiring all code to work in homogenous
     735             :     // coordinates or interpret infinite values correctly, a specialized
     736             :     // clipping function is integrated into ProjectRectBounds.
     737             : 
     738             :     // Callers should pass an aClip value that represents the extents to clip
     739             :     // the result to, in the same coordinate system as aRect.
     740         143 :     Point4DTyped<TargetUnits, F> points[4];
     741             : 
     742         143 :     points[0] = ProjectPoint(aRect.TopLeft());
     743         143 :     points[1] = ProjectPoint(aRect.TopRight());
     744         143 :     points[2] = ProjectPoint(aRect.BottomRight());
     745         143 :     points[3] = ProjectPoint(aRect.BottomLeft());
     746             : 
     747         143 :     F min_x = std::numeric_limits<F>::max();
     748         143 :     F min_y = std::numeric_limits<F>::max();
     749         143 :     F max_x = -std::numeric_limits<F>::max();
     750         143 :     F max_y = -std::numeric_limits<F>::max();
     751             : 
     752         715 :     for (int i=0; i<4; i++) {
     753             :       // Only use points that exist above the w=0 plane
     754         572 :       if (points[i].HasPositiveWCoord()) {
     755         572 :         PointTyped<TargetUnits, F> point2d = aClip.ClampPoint(points[i].As2DPoint());
     756         572 :         min_x = std::min<F>(point2d.x, min_x);
     757         572 :         max_x = std::max<F>(point2d.x, max_x);
     758         572 :         min_y = std::min<F>(point2d.y, min_y);
     759         572 :         max_y = std::max<F>(point2d.y, max_y);
     760             :       }
     761             : 
     762         572 :       int next = (i == 3) ? 0 : i + 1;
     763         572 :       if (points[i].HasPositiveWCoord() != points[next].HasPositiveWCoord()) {
     764             :         // If the line between two points crosses the w=0 plane, then interpolate
     765             :         // to find the point of intersection with the w=0 plane and use that
     766             :         // instead.
     767             :         Point4DTyped<TargetUnits, F> intercept =
     768           0 :           ComputePerspectivePlaneIntercept(points[i], points[next]);
     769             :         // Since intercept.w will always be 0 here, we interpret x,y,z as a
     770             :         // direction towards an infinite vanishing point.
     771           0 :         if (intercept.x < 0.0f) {
     772           0 :           min_x = aClip.x;
     773           0 :         } else if (intercept.x > 0.0f) {
     774           0 :           max_x = aClip.XMost();
     775             :         }
     776           0 :         if (intercept.y < 0.0f) {
     777           0 :           min_y = aClip.y;
     778           0 :         } else if (intercept.y > 0.0f) {
     779           0 :           max_y = aClip.YMost();
     780             :         }
     781             :       }
     782             :     }
     783             : 
     784         143 :     if (max_x < min_x || max_y < min_y) {
     785           0 :       return RectTyped<TargetUnits, F>(0, 0, 0, 0);
     786             :     }
     787             : 
     788         143 :     return RectTyped<TargetUnits, F>(min_x, min_y, max_x - min_x, max_y - min_y);
     789             :   }
     790             : 
     791             :   /**
     792             :    * TransformAndClipBounds transforms aRect as a bounding box, while clipping
     793             :    * the transformed bounds to the extents of aClip.
     794             :    */
     795             :   template<class F>
     796         708 :   RectTyped<TargetUnits, F> TransformAndClipBounds(const RectTyped<SourceUnits, F>& aRect,
     797             :                                                    const RectTyped<TargetUnits, F>& aClip) const
     798             :   {
     799         708 :     PointTyped<UnknownUnits, F> verts[kTransformAndClipRectMaxVerts];
     800         708 :     size_t vertCount = TransformAndClipRect(aRect, aClip, verts);
     801             : 
     802         708 :     F min_x = std::numeric_limits<F>::max();
     803         708 :     F min_y = std::numeric_limits<F>::max();
     804         708 :     F max_x = -std::numeric_limits<F>::max();
     805         708 :     F max_y = -std::numeric_limits<F>::max();
     806        3346 :     for (size_t i=0; i < vertCount; i++) {
     807        2638 :       min_x = std::min(min_x, verts[i].x);
     808        2638 :       max_x = std::max(max_x, verts[i].x);
     809        2638 :       min_y = std::min(min_y, verts[i].y);
     810        2638 :       max_y = std::max(max_y, verts[i].y);
     811             :     }
     812             : 
     813         708 :     if (max_x < min_x || max_y < min_y) {
     814           0 :       return RectTyped<TargetUnits, F>(0, 0, 0, 0);
     815             :     }
     816             : 
     817         708 :     return RectTyped<TargetUnits, F>(min_x, min_y, max_x - min_x, max_y - min_y);
     818             :   }
     819             : 
     820             :   template<class F>
     821             :   RectTyped<TargetUnits, F> TransformAndClipBounds(const TriangleTyped<SourceUnits, F>& aTriangle,
     822             :                                                    const RectTyped<TargetUnits, F>& aClip) const
     823             :   {
     824             :     return TransformAndClipBounds(aTriangle.BoundingBox(), aClip);
     825             :   }
     826             : 
     827             :   /**
     828             :    * TransformAndClipRect projects a rectangle and clips against view frustum
     829             :    * clipping planes in homogenous space so that its projected vertices are
     830             :    * constrained within the 2d rectangle passed in aClip.
     831             :    * The resulting vertices are populated in aVerts.  aVerts must be
     832             :    * pre-allocated to hold at least kTransformAndClipRectMaxVerts Points.
     833             :    * The vertex count is returned by TransformAndClipRect.  It is possible to
     834             :    * emit fewer that 3 vertices, indicating that aRect will not be visible
     835             :    * within aClip.
     836             :    */
     837             :   template<class F>
     838         708 :   size_t TransformAndClipRect(const RectTyped<SourceUnits, F>& aRect,
     839             :                               const RectTyped<TargetUnits, F>& aClip,
     840             :                               PointTyped<TargetUnits, F>* aVerts) const
     841             :   {
     842             :     // Initialize a double-buffered array of points in homogenous space with
     843             :     // the input rectangle, aRect.
     844         708 :     Point4DTyped<UnknownUnits, F> points[2][kTransformAndClipRectMaxVerts];
     845         708 :     Point4DTyped<UnknownUnits, F>* dstPoint = points[0];
     846             : 
     847         708 :     *dstPoint++ = TransformPoint(Point4DTyped<UnknownUnits, F>(aRect.x, aRect.y, 0, 1));
     848         708 :     *dstPoint++ = TransformPoint(Point4DTyped<UnknownUnits, F>(aRect.XMost(), aRect.y, 0, 1));
     849         708 :     *dstPoint++ = TransformPoint(Point4DTyped<UnknownUnits, F>(aRect.XMost(), aRect.YMost(), 0, 1));
     850         708 :     *dstPoint++ = TransformPoint(Point4DTyped<UnknownUnits, F>(aRect.x, aRect.YMost(), 0, 1));
     851             : 
     852             :     // View frustum clipping planes are described as normals originating from
     853             :     // the 0,0,0,0 origin.
     854         708 :     Point4DTyped<UnknownUnits, F> planeNormals[4];
     855         708 :     planeNormals[0] = Point4DTyped<UnknownUnits, F>(1.0, 0.0, 0.0, -aClip.x);
     856         708 :     planeNormals[1] = Point4DTyped<UnknownUnits, F>(-1.0, 0.0, 0.0, aClip.XMost());
     857         708 :     planeNormals[2] = Point4DTyped<UnknownUnits, F>(0.0, 1.0, 0.0, -aClip.y);
     858         708 :     planeNormals[3] = Point4DTyped<UnknownUnits, F>(0.0, -1.0, 0.0, aClip.YMost());
     859             : 
     860             :     // Iterate through each clipping plane and clip the polygon.
     861             :     // In each pass, we double buffer, alternating between points[0] and
     862             :     // points[1].
     863        3540 :     for (int plane=0; plane < 4; plane++) {
     864        2832 :       planeNormals[plane].Normalize();
     865        2832 :       Point4DTyped<UnknownUnits, F>* srcPoint = points[plane & 1];
     866        2832 :       Point4DTyped<UnknownUnits, F>* srcPointEnd = dstPoint;
     867             : 
     868        2832 :       dstPoint = points[~plane & 1];
     869        2832 :       Point4DTyped<UnknownUnits, F>* dstPointStart = dstPoint;
     870             : 
     871        2832 :       Point4DTyped<UnknownUnits, F>* prevPoint = srcPointEnd - 1;
     872        2832 :       F prevDot = planeNormals[plane].DotProduct(*prevPoint);
     873       25488 :       while (srcPoint < srcPointEnd && ((dstPoint - dstPointStart) < kTransformAndClipRectMaxVerts)) {
     874       11328 :         F nextDot = planeNormals[plane].DotProduct(*srcPoint);
     875             : 
     876       11328 :         if ((nextDot >= 0.0) != (prevDot >= 0.0)) {
     877             :           // An intersection with the clipping plane has been detected.
     878             :           // Interpolate to find the intersecting point and emit it.
     879           0 :           F t = -prevDot / (nextDot - prevDot);
     880           0 :           *dstPoint++ = *srcPoint * t + *prevPoint * (1.0 - t);
     881             :         }
     882             : 
     883       11328 :         if (nextDot >= 0.0) {
     884             :           // Emit any source points that are on the positive side of the
     885             :           // clipping plane.
     886       11328 :           *dstPoint++ = *srcPoint;
     887             :         }
     888             : 
     889       11328 :         prevPoint = srcPoint++;
     890       11328 :         prevDot = nextDot;
     891             :       }
     892             : 
     893        2832 :       if (dstPoint == dstPointStart) {
     894           0 :         break;
     895             :       }
     896             :     }
     897             : 
     898         708 :     size_t dstPointCount = 0;
     899         708 :     size_t srcPointCount = dstPoint - points[0];
     900        3540 :     for (Point4DTyped<UnknownUnits, F>* srcPoint = points[0]; srcPoint < points[0] + srcPointCount; srcPoint++) {
     901             : 
     902        2832 :       PointTyped<TargetUnits, F> p;
     903        2832 :       if (srcPoint->w == 0.0) {
     904             :         // If a point lies on the intersection of the clipping planes at
     905             :         // (0,0,0,0), we must avoid a division by zero w component.
     906           0 :         p = PointTyped<TargetUnits, F>(0.0, 0.0);
     907             :       } else {
     908        2832 :         p = srcPoint->As2DPoint();
     909             :       }
     910             :       // Emit only unique points
     911        2832 :       if (dstPointCount == 0 || p != aVerts[dstPointCount - 1]) {
     912        2638 :         aVerts[dstPointCount++] = p;
     913             :       }
     914             :     }
     915             : 
     916         708 :     return dstPointCount;
     917             :   }
     918             : 
     919             :   static const int kTransformAndClipRectMaxVerts = 32;
     920             : 
     921         479 :   static Matrix4x4Typed From2D(const Matrix &aMatrix) {
     922         479 :     Matrix4x4Typed matrix;
     923         479 :     matrix._11 = aMatrix._11;
     924         479 :     matrix._12 = aMatrix._12;
     925         479 :     matrix._21 = aMatrix._21;
     926         479 :     matrix._22 = aMatrix._22;
     927         479 :     matrix._41 = aMatrix._31;
     928         479 :     matrix._42 = aMatrix._32;
     929         479 :     return matrix;
     930             :   }
     931             : 
     932           0 :   bool Is2DIntegerTranslation() const
     933             :   {
     934           0 :     return Is2D() && As2D().IsIntegerTranslation();
     935             :   }
     936             : 
     937           0 :   TargetPoint4D TransposeTransform4D(const SourcePoint4D& aPoint) const
     938             :   {
     939           0 :       Float x = aPoint.x * _11 + aPoint.y * _12 + aPoint.z * _13 + aPoint.w * _14;
     940           0 :       Float y = aPoint.x * _21 + aPoint.y * _22 + aPoint.z * _23 + aPoint.w * _24;
     941           0 :       Float z = aPoint.x * _31 + aPoint.y * _32 + aPoint.z * _33 + aPoint.w * _34;
     942           0 :       Float w = aPoint.x * _41 + aPoint.y * _42 + aPoint.z * _43 + aPoint.w * _44;
     943             : 
     944           0 :       return TargetPoint4D(x, y, z, w);
     945             :   }
     946             : 
     947             :   template<class F>
     948        5629 :   Point4DTyped<TargetUnits, F> TransformPoint(const Point4DTyped<SourceUnits, F>& aPoint) const
     949             :   {
     950        5629 :     Point4DTyped<TargetUnits, F> retPoint;
     951             : 
     952        5629 :     retPoint.x = aPoint.x * _11 + aPoint.y * _21 + aPoint.z * _31 + aPoint.w * _41;
     953        5629 :     retPoint.y = aPoint.x * _12 + aPoint.y * _22 + aPoint.z * _32 + aPoint.w * _42;
     954        5629 :     retPoint.z = aPoint.x * _13 + aPoint.y * _23 + aPoint.z * _33 + aPoint.w * _43;
     955        5629 :     retPoint.w = aPoint.x * _14 + aPoint.y * _24 + aPoint.z * _34 + aPoint.w * _44;
     956             : 
     957        5629 :     return retPoint;
     958             :   }
     959             : 
     960             :   template<class F>
     961           0 :   Point3DTyped<TargetUnits, F> TransformPoint(const Point3DTyped<SourceUnits, F>& aPoint) const
     962             :   {
     963           0 :     Point3DTyped<TargetUnits, F> result;
     964           0 :     result.x = aPoint.x * _11 + aPoint.y * _21 + aPoint.z * _31 + _41;
     965           0 :     result.y = aPoint.x * _12 + aPoint.y * _22 + aPoint.z * _32 + _42;
     966           0 :     result.z = aPoint.x * _13 + aPoint.y * _23 + aPoint.z * _33 + _43;
     967             : 
     968           0 :     result /= (aPoint.x * _14 + aPoint.y * _24 + aPoint.z * _34 + _44);
     969             : 
     970           0 :     return result;
     971             :   }
     972             : 
     973             :   template<class F>
     974        2200 :   PointTyped<TargetUnits, F> TransformPoint(const PointTyped<SourceUnits, F> &aPoint) const
     975             :   {
     976        2200 :     Point4DTyped<SourceUnits, F> temp(aPoint.x, aPoint.y, 0, 1);
     977        2200 :     return TransformPoint(temp).As2DPoint();
     978             :   }
     979             : 
     980             :   template<class F>
     981         550 :   GFX2D_API RectTyped<TargetUnits, F> TransformBounds(const RectTyped<SourceUnits, F>& aRect) const
     982             :   {
     983         550 :     PointTyped<TargetUnits, F> quad[4];
     984             :     F min_x, max_x;
     985             :     F min_y, max_y;
     986             : 
     987         550 :     quad[0] = TransformPoint(aRect.TopLeft());
     988         550 :     quad[1] = TransformPoint(aRect.TopRight());
     989         550 :     quad[2] = TransformPoint(aRect.BottomLeft());
     990         550 :     quad[3] = TransformPoint(aRect.BottomRight());
     991             : 
     992         550 :     min_x = max_x = quad[0].x;
     993         550 :     min_y = max_y = quad[0].y;
     994             : 
     995        2200 :     for (int i = 1; i < 4; i++) {
     996        1650 :       if (quad[i].x < min_x) {
     997           0 :         min_x = quad[i].x;
     998             :       }
     999        1650 :       if (quad[i].x > max_x) {
    1000         534 :         max_x = quad[i].x;
    1001             :       }
    1002             : 
    1003        1650 :       if (quad[i].y < min_y) {
    1004           0 :         min_y = quad[i].y;
    1005             :       }
    1006        1650 :       if (quad[i].y > max_y) {
    1007         534 :         max_y = quad[i].y;
    1008             :       }
    1009             :     }
    1010             : 
    1011         550 :     return RectTyped<TargetUnits, F>(min_x, min_y, max_x - min_x, max_y - min_y);
    1012             :   }
    1013             : 
    1014         622 :   static Matrix4x4Typed Translation(Float aX, Float aY, Float aZ)
    1015             :   {
    1016             :     return Matrix4x4Typed(1.0f, 0.0f, 0.0f, 0.0f,
    1017             :                           0.0f, 1.0f, 0.0f, 0.0f,
    1018             :                           0.0f, 0.0f, 1.0f, 0.0f,
    1019         622 :                           aX,   aY,   aZ, 1.0f);
    1020             :   }
    1021             : 
    1022             :   static Matrix4x4Typed Translation(const TargetPoint3D& aP)
    1023             :   {
    1024             :     return Translation(aP.x, aP.y, aP.z);
    1025             :   }
    1026             : 
    1027           0 :   static Matrix4x4Typed Translation(const TargetPoint& aP)
    1028             :   {
    1029           0 :     return Translation(aP.x, aP.y, 0);
    1030             :   }
    1031             : 
    1032             :   /**
    1033             :    * Apply a translation to this matrix.
    1034             :    *
    1035             :    * The "Pre" in this method's name means that the translation is applied
    1036             :    * -before- this matrix's existing transformation. That is, any vector that
    1037             :    * is multiplied by the resulting matrix will first be translated, then be
    1038             :    * transformed by the original transform.
    1039             :    *
    1040             :    * Calling this method will result in this matrix having the same value as
    1041             :    * the result of:
    1042             :    *
    1043             :    *   Matrix4x4::Translation(x, y) * this
    1044             :    *
    1045             :    * (Note that in performance critical code multiplying by the result of a
    1046             :    * Translation()/Scaling() call is not recommended since that results in a
    1047             :    * full matrix multiply involving 64 floating-point multiplications. Calling
    1048             :    * this method would be preferred since it only involves 12 floating-point
    1049             :    * multiplications.)
    1050             :    */
    1051         230 :   Matrix4x4Typed &PreTranslate(Float aX, Float aY, Float aZ)
    1052             :   {
    1053         230 :     _41 += aX * _11 + aY * _21 + aZ * _31;
    1054         230 :     _42 += aX * _12 + aY * _22 + aZ * _32;
    1055         230 :     _43 += aX * _13 + aY * _23 + aZ * _33;
    1056         230 :     _44 += aX * _14 + aY * _24 + aZ * _34;
    1057             : 
    1058         230 :     return *this;
    1059             :   }
    1060             : 
    1061          36 :   Matrix4x4Typed &PreTranslate(const Point3D& aPoint) {
    1062          36 :     return PreTranslate(aPoint.x, aPoint.y, aPoint.z);
    1063             :   }
    1064             : 
    1065             :   /**
    1066             :    * Similar to PreTranslate, but the translation is applied -after- this
    1067             :    * matrix's existing transformation instead of before it.
    1068             :    *
    1069             :    * This method is generally less used than PreTranslate since typically code
    1070             :    * wants to adjust an existing user space to device space matrix to create a
    1071             :    * transform to device space from a -new- user space (translated from the
    1072             :    * previous user space). In that case consumers will need to use the Pre*
    1073             :    * variants of the matrix methods rather than using the Post* methods, since
    1074             :    * the Post* methods add a transform to the device space end of the
    1075             :    * transformation.
    1076             :    */
    1077         866 :   Matrix4x4Typed &PostTranslate(Float aX, Float aY, Float aZ)
    1078             :   {
    1079         866 :     _11 += _14 * aX;
    1080         866 :     _21 += _24 * aX;
    1081         866 :     _31 += _34 * aX;
    1082         866 :     _41 += _44 * aX;
    1083         866 :     _12 += _14 * aY;
    1084         866 :     _22 += _24 * aY;
    1085         866 :     _32 += _34 * aY;
    1086         866 :     _42 += _44 * aY;
    1087         866 :     _13 += _14 * aZ;
    1088         866 :     _23 += _24 * aZ;
    1089         866 :     _33 += _34 * aZ;
    1090         866 :     _43 += _44 * aZ;
    1091             : 
    1092         866 :     return *this;
    1093             :   }
    1094             : 
    1095         194 :   Matrix4x4Typed &PostTranslate(const TargetPoint3D& aPoint) {
    1096         194 :     return PostTranslate(aPoint.x, aPoint.y, aPoint.z);
    1097             :   }
    1098             : 
    1099           0 :   Matrix4x4Typed &PostTranslate(const TargetPoint& aPoint) {
    1100           0 :     return PostTranslate(aPoint.x, aPoint.y, 0);
    1101             :   }
    1102             : 
    1103         879 :   static Matrix4x4Typed Scaling(Float aScaleX, Float aScaleY, float aScaleZ)
    1104             :   {
    1105             :     return Matrix4x4Typed(aScaleX, 0.0f, 0.0f, 0.0f,
    1106             :                           0.0f, aScaleY, 0.0f, 0.0f,
    1107             :                           0.0f, 0.0f, aScaleZ, 0.0f,
    1108         879 :                           0.0f, 0.0f, 0.0f, 1.0f);
    1109             :   }
    1110             : 
    1111             :   /**
    1112             :    * Similar to PreTranslate, but applies a scale instead of a translation.
    1113             :    */
    1114        2040 :   Matrix4x4Typed &PreScale(Float aX, Float aY, Float aZ)
    1115             :   {
    1116        2040 :     _11 *= aX;
    1117        2040 :     _12 *= aX;
    1118        2040 :     _13 *= aX;
    1119        2040 :     _14 *= aX;
    1120        2040 :     _21 *= aY;
    1121        2040 :     _22 *= aY;
    1122        2040 :     _23 *= aY;
    1123        2040 :     _24 *= aY;
    1124        2040 :     _31 *= aZ;
    1125        2040 :     _32 *= aZ;
    1126        2040 :     _33 *= aZ;
    1127        2040 :     _34 *= aZ;
    1128             : 
    1129        2040 :     return *this;
    1130             :   }
    1131             : 
    1132             :   /**
    1133             :    * Similar to PostTranslate, but applies a scale instead of a translation.
    1134             :    */
    1135        3904 :   Matrix4x4Typed &PostScale(Float aScaleX, Float aScaleY, Float aScaleZ)
    1136             :   {
    1137        3904 :     _11 *= aScaleX;
    1138        3904 :     _21 *= aScaleX;
    1139        3904 :     _31 *= aScaleX;
    1140        3904 :     _41 *= aScaleX;
    1141        3904 :     _12 *= aScaleY;
    1142        3904 :     _22 *= aScaleY;
    1143        3904 :     _32 *= aScaleY;
    1144        3904 :     _42 *= aScaleY;
    1145        3904 :     _13 *= aScaleZ;
    1146        3904 :     _23 *= aScaleZ;
    1147        3904 :     _33 *= aScaleZ;
    1148        3904 :     _43 *= aScaleZ;
    1149             : 
    1150        3904 :     return *this;
    1151             :   }
    1152             : 
    1153           0 :   void SkewXY(Float aSkew)
    1154             :   {
    1155           0 :     (*this)[1] += (*this)[0] * aSkew;
    1156           0 :   }
    1157             : 
    1158           0 :   void SkewXZ(Float aSkew)
    1159             :   {
    1160           0 :       (*this)[2] += (*this)[0] * aSkew;
    1161           0 :   }
    1162             : 
    1163           0 :   void SkewYZ(Float aSkew)
    1164             :   {
    1165           0 :       (*this)[2] += (*this)[1] * aSkew;
    1166           0 :   }
    1167             : 
    1168         194 :   Matrix4x4Typed &ChangeBasis(const Point3D& aOrigin)
    1169             :   {
    1170         194 :     return ChangeBasis(aOrigin.x, aOrigin.y, aOrigin.z);
    1171             :   }
    1172             : 
    1173         194 :   Matrix4x4Typed &ChangeBasis(Float aX, Float aY, Float aZ)
    1174             :   {
    1175             :     // Translate to the origin before applying this matrix
    1176         194 :     PreTranslate(-aX, -aY, -aZ);
    1177             : 
    1178             :     // Translate back into position after applying this matrix
    1179         194 :     PostTranslate(aX, aY, aZ);
    1180             : 
    1181         194 :     return *this;
    1182             :   }
    1183             : 
    1184           0 :   Matrix4x4Typed& Transpose() {
    1185           0 :     std::swap(_12, _21);
    1186           0 :     std::swap(_13, _31);
    1187           0 :     std::swap(_14, _41);
    1188             : 
    1189           0 :     std::swap(_23, _32);
    1190           0 :     std::swap(_24, _42);
    1191             : 
    1192           0 :     std::swap(_34, _43);
    1193             : 
    1194           0 :     return *this;
    1195             :   }
    1196             : 
    1197         548 :   bool operator==(const Matrix4x4Typed& o) const
    1198             :   {
    1199             :     // XXX would be nice to memcmp here, but that breaks IEEE 754 semantics
    1200        1614 :     return _11 == o._11 && _12 == o._12 && _13 == o._13 && _14 == o._14 &&
    1201        1599 :            _21 == o._21 && _22 == o._22 && _23 == o._23 && _24 == o._24 &&
    1202        1599 :            _31 == o._31 && _32 == o._32 && _33 == o._33 && _34 == o._34 &&
    1203        1539 :            _41 == o._41 && _42 == o._42 && _43 == o._43 && _44 == o._44;
    1204             :   }
    1205             : 
    1206          24 :   bool operator!=(const Matrix4x4Typed& o) const
    1207             :   {
    1208          24 :     return !((*this) == o);
    1209             :   }
    1210             : 
    1211             :   template <typename NewTargetUnits>
    1212        2018 :   Matrix4x4Typed<SourceUnits, NewTargetUnits> operator*(const Matrix4x4Typed<TargetUnits, NewTargetUnits> &aMatrix) const
    1213             :   {
    1214        2018 :     Matrix4x4Typed<SourceUnits, NewTargetUnits> matrix;
    1215             : 
    1216        2018 :     matrix._11 = _11 * aMatrix._11 + _12 * aMatrix._21 + _13 * aMatrix._31 + _14 * aMatrix._41;
    1217        2018 :     matrix._21 = _21 * aMatrix._11 + _22 * aMatrix._21 + _23 * aMatrix._31 + _24 * aMatrix._41;
    1218        2018 :     matrix._31 = _31 * aMatrix._11 + _32 * aMatrix._21 + _33 * aMatrix._31 + _34 * aMatrix._41;
    1219        2018 :     matrix._41 = _41 * aMatrix._11 + _42 * aMatrix._21 + _43 * aMatrix._31 + _44 * aMatrix._41;
    1220        2018 :     matrix._12 = _11 * aMatrix._12 + _12 * aMatrix._22 + _13 * aMatrix._32 + _14 * aMatrix._42;
    1221        2018 :     matrix._22 = _21 * aMatrix._12 + _22 * aMatrix._22 + _23 * aMatrix._32 + _24 * aMatrix._42;
    1222        2018 :     matrix._32 = _31 * aMatrix._12 + _32 * aMatrix._22 + _33 * aMatrix._32 + _34 * aMatrix._42;
    1223        2018 :     matrix._42 = _41 * aMatrix._12 + _42 * aMatrix._22 + _43 * aMatrix._32 + _44 * aMatrix._42;
    1224        2018 :     matrix._13 = _11 * aMatrix._13 + _12 * aMatrix._23 + _13 * aMatrix._33 + _14 * aMatrix._43;
    1225        2018 :     matrix._23 = _21 * aMatrix._13 + _22 * aMatrix._23 + _23 * aMatrix._33 + _24 * aMatrix._43;
    1226        2018 :     matrix._33 = _31 * aMatrix._13 + _32 * aMatrix._23 + _33 * aMatrix._33 + _34 * aMatrix._43;
    1227        2018 :     matrix._43 = _41 * aMatrix._13 + _42 * aMatrix._23 + _43 * aMatrix._33 + _44 * aMatrix._43;
    1228        2018 :     matrix._14 = _11 * aMatrix._14 + _12 * aMatrix._24 + _13 * aMatrix._34 + _14 * aMatrix._44;
    1229        2018 :     matrix._24 = _21 * aMatrix._14 + _22 * aMatrix._24 + _23 * aMatrix._34 + _24 * aMatrix._44;
    1230        2018 :     matrix._34 = _31 * aMatrix._14 + _32 * aMatrix._24 + _33 * aMatrix._34 + _34 * aMatrix._44;
    1231        2018 :     matrix._44 = _41 * aMatrix._14 + _42 * aMatrix._24 + _43 * aMatrix._34 + _44 * aMatrix._44;
    1232             : 
    1233        2018 :     return matrix;
    1234             :   }
    1235             : 
    1236          69 :   Matrix4x4Typed& operator*=(const Matrix4x4Typed<TargetUnits, TargetUnits> &aMatrix)
    1237             :   {
    1238          69 :     *this = *this * aMatrix;
    1239          69 :     return *this;
    1240             :   }
    1241             : 
    1242             :   /* Returns true if the matrix is an identity matrix.
    1243             :    */
    1244         300 :   bool IsIdentity() const
    1245             :   {
    1246         810 :     return _11 == 1.0f && _12 == 0.0f && _13 == 0.0f && _14 == 0.0f &&
    1247         765 :            _21 == 0.0f && _22 == 1.0f && _23 == 0.0f && _24 == 0.0f &&
    1248         765 :            _31 == 0.0f && _32 == 0.0f && _33 == 1.0f && _34 == 0.0f &&
    1249         795 :            _41 == 0.0f && _42 == 0.0f && _43 == 0.0f && _44 == 1.0f;
    1250             :   }
    1251             : 
    1252        1343 :   bool IsSingular() const
    1253             :   {
    1254        1343 :     return Determinant() == 0.0;
    1255             :   }
    1256             : 
    1257        1516 :   Float Determinant() const
    1258             :   {
    1259        1516 :     return _14 * _23 * _32 * _41
    1260        1516 :          - _13 * _24 * _32 * _41
    1261        1516 :          - _14 * _22 * _33 * _41
    1262        1516 :          + _12 * _24 * _33 * _41
    1263        1516 :          + _13 * _22 * _34 * _41
    1264        1516 :          - _12 * _23 * _34 * _41
    1265        1516 :          - _14 * _23 * _31 * _42
    1266        1516 :          + _13 * _24 * _31 * _42
    1267        1516 :          + _14 * _21 * _33 * _42
    1268        1516 :          - _11 * _24 * _33 * _42
    1269        1516 :          - _13 * _21 * _34 * _42
    1270        1516 :          + _11 * _23 * _34 * _42
    1271        1516 :          + _14 * _22 * _31 * _43
    1272        1516 :          - _12 * _24 * _31 * _43
    1273        1516 :          - _14 * _21 * _32 * _43
    1274        1516 :          + _11 * _24 * _32 * _43
    1275        1516 :          + _12 * _21 * _34 * _43
    1276        1516 :          - _11 * _22 * _34 * _43
    1277        1516 :          - _13 * _22 * _31 * _44
    1278        1516 :          + _12 * _23 * _31 * _44
    1279        1516 :          + _13 * _21 * _32 * _44
    1280        1516 :          - _11 * _23 * _32 * _44
    1281        1516 :          - _12 * _21 * _33 * _44
    1282        1516 :          + _11 * _22 * _33 * _44;
    1283             :   }
    1284             : 
    1285             :   // Invert() is not unit-correct. Prefer Inverse() where possible.
    1286         173 :   bool Invert()
    1287             :   {
    1288         173 :     Float det = Determinant();
    1289         173 :     if (!det) {
    1290           0 :       return false;
    1291             :     }
    1292             : 
    1293         173 :     Matrix4x4Typed<SourceUnits, TargetUnits> result;
    1294         173 :     result._11 = _23 * _34 * _42 - _24 * _33 * _42 + _24 * _32 * _43 - _22 * _34 * _43 - _23 * _32 * _44 + _22 * _33 * _44;
    1295         173 :     result._12 = _14 * _33 * _42 - _13 * _34 * _42 - _14 * _32 * _43 + _12 * _34 * _43 + _13 * _32 * _44 - _12 * _33 * _44;
    1296         173 :     result._13 = _13 * _24 * _42 - _14 * _23 * _42 + _14 * _22 * _43 - _12 * _24 * _43 - _13 * _22 * _44 + _12 * _23 * _44;
    1297         173 :     result._14 = _14 * _23 * _32 - _13 * _24 * _32 - _14 * _22 * _33 + _12 * _24 * _33 + _13 * _22 * _34 - _12 * _23 * _34;
    1298         173 :     result._21 = _24 * _33 * _41 - _23 * _34 * _41 - _24 * _31 * _43 + _21 * _34 * _43 + _23 * _31 * _44 - _21 * _33 * _44;
    1299         173 :     result._22 = _13 * _34 * _41 - _14 * _33 * _41 + _14 * _31 * _43 - _11 * _34 * _43 - _13 * _31 * _44 + _11 * _33 * _44;
    1300         173 :     result._23 = _14 * _23 * _41 - _13 * _24 * _41 - _14 * _21 * _43 + _11 * _24 * _43 + _13 * _21 * _44 - _11 * _23 * _44;
    1301         173 :     result._24 = _13 * _24 * _31 - _14 * _23 * _31 + _14 * _21 * _33 - _11 * _24 * _33 - _13 * _21 * _34 + _11 * _23 * _34;
    1302         173 :     result._31 = _22 * _34 * _41 - _24 * _32 * _41 + _24 * _31 * _42 - _21 * _34 * _42 - _22 * _31 * _44 + _21 * _32 * _44;
    1303         173 :     result._32 = _14 * _32 * _41 - _12 * _34 * _41 - _14 * _31 * _42 + _11 * _34 * _42 + _12 * _31 * _44 - _11 * _32 * _44;
    1304         173 :     result._33 = _12 * _24 * _41 - _14 * _22 * _41 + _14 * _21 * _42 - _11 * _24 * _42 - _12 * _21 * _44 + _11 * _22 * _44;
    1305         173 :     result._34 = _14 * _22 * _31 - _12 * _24 * _31 - _14 * _21 * _32 + _11 * _24 * _32 + _12 * _21 * _34 - _11 * _22 * _34;
    1306         173 :     result._41 = _23 * _32 * _41 - _22 * _33 * _41 - _23 * _31 * _42 + _21 * _33 * _42 + _22 * _31 * _43 - _21 * _32 * _43;
    1307         173 :     result._42 = _12 * _33 * _41 - _13 * _32 * _41 + _13 * _31 * _42 - _11 * _33 * _42 - _12 * _31 * _43 + _11 * _32 * _43;
    1308         173 :     result._43 = _13 * _22 * _41 - _12 * _23 * _41 - _13 * _21 * _42 + _11 * _23 * _42 + _12 * _21 * _43 - _11 * _22 * _43;
    1309         173 :     result._44 = _12 * _23 * _31 - _13 * _22 * _31 + _13 * _21 * _32 - _11 * _23 * _32 - _12 * _21 * _33 + _11 * _22 * _33;
    1310             : 
    1311         173 :     result._11 /= det;
    1312         173 :     result._12 /= det;
    1313         173 :     result._13 /= det;
    1314         173 :     result._14 /= det;
    1315         173 :     result._21 /= det;
    1316         173 :     result._22 /= det;
    1317         173 :     result._23 /= det;
    1318         173 :     result._24 /= det;
    1319         173 :     result._31 /= det;
    1320         173 :     result._32 /= det;
    1321         173 :     result._33 /= det;
    1322         173 :     result._34 /= det;
    1323         173 :     result._41 /= det;
    1324         173 :     result._42 /= det;
    1325         173 :     result._43 /= det;
    1326         173 :     result._44 /= det;
    1327         173 :     *this = result;
    1328             : 
    1329         173 :     return true;
    1330             :   }
    1331             : 
    1332          38 :   Matrix4x4Typed<TargetUnits, SourceUnits> Inverse() const
    1333             :   {
    1334             :     typedef Matrix4x4Typed<TargetUnits, SourceUnits> InvertedMatrix;
    1335          38 :     InvertedMatrix clone = InvertedMatrix::FromUnknownMatrix(ToUnknownMatrix());
    1336          76 :     DebugOnly<bool> inverted = clone.Invert();
    1337          38 :     MOZ_ASSERT(inverted, "Attempted to get the inverse of a non-invertible matrix");
    1338          76 :     return clone;
    1339             :   }
    1340             : 
    1341          20 :   Maybe<Matrix4x4Typed<TargetUnits, SourceUnits>> MaybeInverse() const
    1342             :   {
    1343             :     typedef Matrix4x4Typed<TargetUnits, SourceUnits> InvertedMatrix;
    1344          20 :     InvertedMatrix clone = InvertedMatrix::FromUnknownMatrix(ToUnknownMatrix());
    1345          20 :     if (clone.Invert()) {
    1346          20 :       return Some(clone);
    1347             :     }
    1348           0 :     return Nothing();
    1349             :   }
    1350             :   
    1351           0 :   void Normalize()
    1352             :   {
    1353           0 :       for (int i = 0; i < 4; i++) {
    1354           0 :           for (int j = 0; j < 4; j++) {
    1355           0 :               (*this)[i][j] /= (*this)[3][3];
    1356             :          }
    1357             :       }
    1358           0 :   }
    1359             : 
    1360         510 :   bool FuzzyEqual(const Matrix4x4Typed& o) const
    1361             :   {
    1362        1530 :     return gfx::FuzzyEqual(_11, o._11) && gfx::FuzzyEqual(_12, o._12) &&
    1363        1530 :            gfx::FuzzyEqual(_13, o._13) && gfx::FuzzyEqual(_14, o._14) &&
    1364        1530 :            gfx::FuzzyEqual(_21, o._21) && gfx::FuzzyEqual(_22, o._22) &&
    1365        1530 :            gfx::FuzzyEqual(_23, o._23) && gfx::FuzzyEqual(_24, o._24) &&
    1366        1530 :            gfx::FuzzyEqual(_31, o._31) && gfx::FuzzyEqual(_32, o._32) &&
    1367        1530 :            gfx::FuzzyEqual(_33, o._33) && gfx::FuzzyEqual(_34, o._34) &&
    1368        1518 :            gfx::FuzzyEqual(_41, o._41) && gfx::FuzzyEqual(_42, o._42) &&
    1369        1518 :            gfx::FuzzyEqual(_43, o._43) && gfx::FuzzyEqual(_44, o._44);
    1370             :   }
    1371             : 
    1372           5 :   bool FuzzyEqualsMultiplicative(const Matrix4x4Typed& o) const
    1373             :   {
    1374          10 :     return ::mozilla::FuzzyEqualsMultiplicative(_11, o._11) &&
    1375          10 :            ::mozilla::FuzzyEqualsMultiplicative(_12, o._12) &&
    1376          10 :            ::mozilla::FuzzyEqualsMultiplicative(_13, o._13) &&
    1377          10 :            ::mozilla::FuzzyEqualsMultiplicative(_14, o._14) &&
    1378          10 :            ::mozilla::FuzzyEqualsMultiplicative(_21, o._21) &&
    1379          10 :            ::mozilla::FuzzyEqualsMultiplicative(_22, o._22) &&
    1380          10 :            ::mozilla::FuzzyEqualsMultiplicative(_23, o._23) &&
    1381          10 :            ::mozilla::FuzzyEqualsMultiplicative(_24, o._24) &&
    1382          10 :            ::mozilla::FuzzyEqualsMultiplicative(_31, o._31) &&
    1383          10 :            ::mozilla::FuzzyEqualsMultiplicative(_32, o._32) &&
    1384          10 :            ::mozilla::FuzzyEqualsMultiplicative(_33, o._33) &&
    1385          10 :            ::mozilla::FuzzyEqualsMultiplicative(_34, o._34) &&
    1386          10 :            ::mozilla::FuzzyEqualsMultiplicative(_41, o._41) &&
    1387          10 :            ::mozilla::FuzzyEqualsMultiplicative(_42, o._42) &&
    1388          15 :            ::mozilla::FuzzyEqualsMultiplicative(_43, o._43) &&
    1389          10 :            ::mozilla::FuzzyEqualsMultiplicative(_44, o._44);
    1390             :   }
    1391             : 
    1392           0 :   bool IsBackfaceVisible() const
    1393             :   {
    1394             :     // Inverse()._33 < 0;
    1395           0 :     Float det = Determinant();
    1396           0 :     Float __33 = _12*_24*_41 - _14*_22*_41 +
    1397           0 :                 _14*_21*_42 - _11*_24*_42 -
    1398           0 :                 _12*_21*_44 + _11*_22*_44;
    1399           0 :     return (__33 * det) < 0;
    1400             :   }
    1401             : 
    1402          24 :   Matrix4x4Typed &NudgeToIntegersFixedEpsilon()
    1403             :   {
    1404          24 :     NudgeToInteger(&_11);
    1405          24 :     NudgeToInteger(&_12);
    1406          24 :     NudgeToInteger(&_13);
    1407          24 :     NudgeToInteger(&_14);
    1408          24 :     NudgeToInteger(&_21);
    1409          24 :     NudgeToInteger(&_22);
    1410          24 :     NudgeToInteger(&_23);
    1411          24 :     NudgeToInteger(&_24);
    1412          24 :     NudgeToInteger(&_31);
    1413          24 :     NudgeToInteger(&_32);
    1414          24 :     NudgeToInteger(&_33);
    1415          24 :     NudgeToInteger(&_34);
    1416             :     static const float error = 1e-5f;
    1417          24 :     NudgeToInteger(&_41, error);
    1418          24 :     NudgeToInteger(&_42, error);
    1419          24 :     NudgeToInteger(&_43, error);
    1420          24 :     NudgeToInteger(&_44, error);
    1421          24 :     return *this;
    1422             :   }
    1423             : 
    1424           0 :   Point4D TransposedVector(int aIndex) const
    1425             :   {
    1426           0 :       MOZ_ASSERT(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index");
    1427           0 :       return Point4D(*((&_11)+aIndex), *((&_21)+aIndex), *((&_31)+aIndex), *((&_41)+aIndex));
    1428             :   }
    1429             : 
    1430           0 :   void SetTransposedVector(int aIndex, Point4D &aVector)
    1431             :   {
    1432           0 :       MOZ_ASSERT(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index");
    1433           0 :       *((&_11)+aIndex) = aVector.x;
    1434           0 :       *((&_21)+aIndex) = aVector.y;
    1435           0 :       *((&_31)+aIndex) = aVector.z;
    1436           0 :       *((&_41)+aIndex) = aVector.w;
    1437           0 :   }
    1438             : 
    1439             :   // Sets this matrix to a rotation matrix given by aQuat.
    1440             :   // This quaternion *MUST* be normalized!
    1441             :   // Implemented in Quaternion.cpp
    1442           0 :   void SetRotationFromQuaternion(const Quaternion& q)
    1443             :   {
    1444           0 :     const Float x2 = q.x + q.x, y2 = q.y + q.y, z2 = q.z + q.z;
    1445           0 :     const Float xx = q.x * x2, xy = q.x * y2, xz = q.x * z2;
    1446           0 :     const Float yy = q.y * y2, yz = q.y * z2, zz = q.z * z2;
    1447           0 :     const Float wx = q.w * x2, wy = q.w * y2, wz = q.w * z2;
    1448             : 
    1449           0 :     _11 = 1.0f - (yy + zz);
    1450           0 :     _21 = xy + wz;
    1451           0 :     _31 = xz - wy;
    1452           0 :     _41 = 0.0f;
    1453             : 
    1454           0 :     _12 = xy - wz;
    1455           0 :     _22 = 1.0f - (xx + zz);
    1456           0 :     _32 = yz + wx;
    1457           0 :     _42 = 0.0f;
    1458             : 
    1459           0 :     _13 = xz + wy;
    1460           0 :     _23 = yz - wx;
    1461           0 :     _33 = 1.0f - (xx + yy);
    1462           0 :     _43 = 0.0f;
    1463             : 
    1464           0 :     _14 = _42 = _43 = 0.0f;
    1465           0 :     _44 = 1.0f;
    1466           0 :   }
    1467             : 
    1468             :   // Set all the members of the matrix to NaN
    1469           0 :   void SetNAN()
    1470             :   {
    1471           0 :     _11 = UnspecifiedNaN<Float>();
    1472           0 :     _21 = UnspecifiedNaN<Float>();
    1473           0 :     _31 = UnspecifiedNaN<Float>();
    1474           0 :     _41 = UnspecifiedNaN<Float>();
    1475           0 :     _12 = UnspecifiedNaN<Float>();
    1476           0 :     _22 = UnspecifiedNaN<Float>();
    1477           0 :     _32 = UnspecifiedNaN<Float>();
    1478           0 :     _42 = UnspecifiedNaN<Float>();
    1479           0 :     _13 = UnspecifiedNaN<Float>();
    1480           0 :     _23 = UnspecifiedNaN<Float>();
    1481           0 :     _33 = UnspecifiedNaN<Float>();
    1482           0 :     _43 = UnspecifiedNaN<Float>();
    1483           0 :     _14 = UnspecifiedNaN<Float>();
    1484           0 :     _24 = UnspecifiedNaN<Float>();
    1485           0 :     _34 = UnspecifiedNaN<Float>();
    1486           0 :     _44 = UnspecifiedNaN<Float>();
    1487           0 :   }
    1488             : 
    1489           0 :   void SkewXY(double aXSkew, double aYSkew)
    1490             :   {
    1491             :     // XXX Is double precision really necessary here
    1492           0 :     float tanX = SafeTangent(aXSkew);
    1493           0 :     float tanY = SafeTangent(aYSkew);
    1494             :     float temp;
    1495             : 
    1496           0 :     temp = _11;
    1497           0 :     _11 += tanY * _21;
    1498           0 :     _21 += tanX * temp;
    1499             : 
    1500           0 :     temp = _12;
    1501           0 :     _12 += tanY * _22;
    1502           0 :     _22 += tanX * temp;
    1503             : 
    1504           0 :     temp = _13;
    1505           0 :     _13 += tanY * _23;
    1506           0 :     _23 += tanX * temp;
    1507             : 
    1508           0 :     temp = _14;
    1509           0 :     _14 += tanY * _24;
    1510           0 :     _24 += tanX * temp;
    1511           0 :   }
    1512             : 
    1513           0 :   void RotateX(double aTheta)
    1514             :   {
    1515             :     // XXX Is double precision really necessary here
    1516           0 :     double cosTheta = FlushToZero(cos(aTheta));
    1517           0 :     double sinTheta = FlushToZero(sin(aTheta));
    1518             : 
    1519             :     float temp;
    1520             : 
    1521           0 :     temp = _21;
    1522           0 :     _21 = cosTheta * _21 + sinTheta * _31;
    1523           0 :     _31 = -sinTheta * temp + cosTheta * _31;
    1524             : 
    1525           0 :     temp = _22;
    1526           0 :     _22 = cosTheta * _22 + sinTheta * _32;
    1527           0 :     _32 = -sinTheta * temp + cosTheta * _32;
    1528             : 
    1529           0 :     temp = _23;
    1530           0 :     _23 = cosTheta * _23 + sinTheta * _33;
    1531           0 :     _33 = -sinTheta * temp + cosTheta * _33;
    1532             : 
    1533           0 :     temp = _24;
    1534           0 :     _24 = cosTheta * _24 + sinTheta * _34;
    1535           0 :     _34 = -sinTheta * temp + cosTheta * _34;
    1536           0 :   }
    1537             : 
    1538           0 :   void RotateY(double aTheta)
    1539             :   {
    1540             :     // XXX Is double precision really necessary here
    1541           0 :     double cosTheta = FlushToZero(cos(aTheta));
    1542           0 :     double sinTheta = FlushToZero(sin(aTheta));
    1543             : 
    1544             :     float temp;
    1545             : 
    1546           0 :     temp = _11;
    1547           0 :     _11 = cosTheta * _11 + -sinTheta * _31;
    1548           0 :     _31 = sinTheta * temp + cosTheta * _31;
    1549             : 
    1550           0 :     temp = _12;
    1551           0 :     _12 = cosTheta * _12 + -sinTheta * _32;
    1552           0 :     _32 = sinTheta * temp + cosTheta * _32;
    1553             : 
    1554           0 :     temp = _13;
    1555           0 :     _13 = cosTheta * _13 + -sinTheta * _33;
    1556           0 :     _33 = sinTheta * temp + cosTheta * _33;
    1557             : 
    1558           0 :     temp = _14;
    1559           0 :     _14 = cosTheta * _14 + -sinTheta * _34;
    1560           0 :     _34 = sinTheta * temp + cosTheta * _34;
    1561           0 :   }
    1562             : 
    1563           0 :   void RotateZ(double aTheta)
    1564             :   {
    1565             :     // XXX Is double precision really necessary here
    1566           0 :     double cosTheta = FlushToZero(cos(aTheta));
    1567           0 :     double sinTheta = FlushToZero(sin(aTheta));
    1568             : 
    1569             :     float temp;
    1570             : 
    1571           0 :     temp = _11;
    1572           0 :     _11 = cosTheta * _11 + sinTheta * _21;
    1573           0 :     _21 = -sinTheta * temp + cosTheta * _21;
    1574             : 
    1575           0 :     temp = _12;
    1576           0 :     _12 = cosTheta * _12 + sinTheta * _22;
    1577           0 :     _22 = -sinTheta * temp + cosTheta * _22;
    1578             : 
    1579           0 :     temp = _13;
    1580           0 :     _13 = cosTheta * _13 + sinTheta * _23;
    1581           0 :     _23 = -sinTheta * temp + cosTheta * _23;
    1582             : 
    1583           0 :     temp = _14;
    1584           0 :     _14 = cosTheta * _14 + sinTheta * _24;
    1585           0 :     _24 = -sinTheta * temp + cosTheta * _24;
    1586           0 :   }
    1587             : 
    1588             :   // Sets this matrix to a rotation matrix about a
    1589             :   // vector [x,y,z] by angle theta. The vector is normalized
    1590             :   // to a unit vector.
    1591             :   // https://www.w3.org/TR/css3-3d-transforms/#Rotate3dDefined
    1592           0 :   void SetRotateAxisAngle(double aX, double aY, double aZ, double aTheta)
    1593             :   {
    1594           0 :     Point3D vector(aX, aY, aZ);
    1595           0 :     if (!vector.Length()) {
    1596           0 :       return;
    1597             :     }
    1598           0 :     vector.Normalize();
    1599             : 
    1600           0 :     double x = vector.x;
    1601           0 :     double y = vector.y;
    1602           0 :     double z = vector.z;
    1603             : 
    1604           0 :     double cosTheta = FlushToZero(cos(aTheta));
    1605           0 :     double sinTheta = FlushToZero(sin(aTheta));
    1606             : 
    1607             :     // sin(aTheta / 2) * cos(aTheta / 2)
    1608           0 :     double sc = sinTheta / 2;
    1609             :     // pow(sin(aTheta / 2), 2)
    1610           0 :     double sq = (1 - cosTheta) / 2;
    1611             : 
    1612           0 :     _11 = 1 - 2 * (y * y + z * z) * sq;
    1613           0 :     _12 = 2 * (x * y * sq + z * sc);
    1614           0 :     _13 = 2 * (x * z * sq - y * sc);
    1615           0 :     _14 = 0.0f;
    1616           0 :     _21 = 2 * (x * y * sq - z * sc);
    1617           0 :     _22 = 1 - 2 * (x * x + z * z) * sq;
    1618           0 :     _23 = 2 * (y * z * sq + x * sc);
    1619           0 :     _24 = 0.0f;
    1620           0 :     _31 = 2 * (x * z * sq + y * sc);
    1621           0 :     _32 = 2 * (y * z * sq - x * sc);
    1622           0 :     _33 = 1 - 2 * (x * x + y * y) * sq;
    1623           0 :     _34 = 0.0f;
    1624           0 :     _41 = 0.0f;
    1625           0 :     _42 = 0.0f;
    1626           0 :     _43 = 0.0f;
    1627           0 :     _44 = 1.0f;
    1628             :   }
    1629             : 
    1630           0 :   void Perspective(float aDepth)
    1631             :   {
    1632           0 :     MOZ_ASSERT(aDepth > 0.0f, "Perspective must be positive!");
    1633           0 :     _31 += -1.0/aDepth * _41;
    1634           0 :     _32 += -1.0/aDepth * _42;
    1635           0 :     _33 += -1.0/aDepth * _43;
    1636           0 :     _34 += -1.0/aDepth * _44;
    1637           0 :   }
    1638             : 
    1639           0 :   Point3D GetNormalVector() const
    1640             :   {
    1641             :     // Define a plane in transformed space as the transformations
    1642             :     // of 3 points on the z=0 screen plane.
    1643           0 :     Point3D a = TransformPoint(Point3D(0, 0, 0));
    1644           0 :     Point3D b = TransformPoint(Point3D(0, 1, 0));
    1645           0 :     Point3D c = TransformPoint(Point3D(1, 0, 0));
    1646             : 
    1647             :     // Convert to two vectors on the surface of the plane.
    1648           0 :     Point3D ab = b - a;
    1649           0 :     Point3D ac = c - a;
    1650             : 
    1651           0 :     return ac.CrossProduct(ab);
    1652             :   }
    1653             : 
    1654             :   /**
    1655             :    * Returns true if the matrix has any transform other
    1656             :    * than a straight translation.
    1657             :    */
    1658         406 :   bool HasNonTranslation() const {
    1659        1218 :     return !gfx::FuzzyEqual(_11, 1.0) || !gfx::FuzzyEqual(_22, 1.0) ||
    1660        1218 :            !gfx::FuzzyEqual(_12, 0.0) || !gfx::FuzzyEqual(_21, 0.0) ||
    1661        1218 :            !gfx::FuzzyEqual(_13, 0.0) || !gfx::FuzzyEqual(_23, 0.0) ||
    1662        1624 :            !gfx::FuzzyEqual(_31, 0.0) || !gfx::FuzzyEqual(_32, 0.0) ||
    1663         812 :            !gfx::FuzzyEqual(_33, 1.0);
    1664             :   }
    1665             : 
    1666             :   /**
    1667             :    * Returns true if the matrix is anything other than a straight
    1668             :    * translation by integers.
    1669             :   */
    1670         203 :   bool HasNonIntegerTranslation() const {
    1671         406 :     return HasNonTranslation() ||
    1672         406 :       !gfx::FuzzyEqual(_41, floor(_41 + 0.5)) ||
    1673         609 :       !gfx::FuzzyEqual(_42, floor(_42 + 0.5)) ||
    1674         406 :       !gfx::FuzzyEqual(_43, floor(_43 + 0.5));
    1675             :   }
    1676             : 
    1677             :   /**
    1678             :    * Return true if the matrix is with perspective (w).
    1679             :    */
    1680         318 :   bool HasPerspectiveComponent() const {
    1681         318 :     return _14 != 0 || _24 != 0 || _34 != 0 || _44 != 1;
    1682             :   }
    1683             : 
    1684             :   /* Returns true if the matrix is a rectilinear transformation (i.e.
    1685             :    * grid-aligned rectangles are transformed to grid-aligned rectangles).
    1686             :    * This should only be called on 2D matrices.
    1687             :    */
    1688             :   bool IsRectilinear() const {
    1689             :     MOZ_ASSERT(Is2D());
    1690             :     if (gfx::FuzzyEqual(_12, 0) && gfx::FuzzyEqual(_21, 0)) {
    1691             :       return true;
    1692             :     } else if (gfx::FuzzyEqual(_22, 0) && gfx::FuzzyEqual(_11, 0)) {
    1693             :       return true;
    1694             :     }
    1695             :     return false;
    1696             :   }
    1697             : 
    1698             :   /**
    1699             :    * Convert between typed and untyped matrices.
    1700             :    */
    1701         339 :   Matrix4x4 ToUnknownMatrix() const {
    1702         339 :     return Matrix4x4{_11, _12, _13, _14,
    1703         339 :                      _21, _22, _23, _24,
    1704         339 :                      _31, _32, _33, _34,
    1705         339 :                      _41, _42, _43, _44};
    1706             :   }
    1707         919 :   static Matrix4x4Typed FromUnknownMatrix(const Matrix4x4& aUnknown) {
    1708         919 :     return Matrix4x4Typed{aUnknown._11, aUnknown._12, aUnknown._13, aUnknown._14,
    1709         919 :                           aUnknown._21, aUnknown._22, aUnknown._23, aUnknown._24,
    1710         919 :                           aUnknown._31, aUnknown._32, aUnknown._33, aUnknown._34,
    1711         919 :                           aUnknown._41, aUnknown._42, aUnknown._43, aUnknown._44};
    1712             :   }
    1713             : };
    1714             : 
    1715             : typedef Matrix4x4Typed<UnknownUnits, UnknownUnits> Matrix4x4;
    1716             : 
    1717             : class Matrix5x4
    1718             : {
    1719             : public:
    1720           0 :   Matrix5x4()
    1721           0 :     : _11(1.0f), _12(0), _13(0), _14(0)
    1722             :     , _21(0), _22(1.0f), _23(0), _24(0)
    1723             :     , _31(0), _32(0), _33(1.0f), _34(0)
    1724             :     , _41(0), _42(0), _43(0), _44(1.0f)
    1725           0 :     , _51(0), _52(0), _53(0), _54(0)
    1726           0 :   {}
    1727           0 :   Matrix5x4(Float a11, Float a12, Float a13, Float a14,
    1728             :          Float a21, Float a22, Float a23, Float a24,
    1729             :          Float a31, Float a32, Float a33, Float a34,
    1730             :          Float a41, Float a42, Float a43, Float a44,
    1731             :          Float a51, Float a52, Float a53, Float a54)
    1732           0 :     : _11(a11), _12(a12), _13(a13), _14(a14)
    1733             :     , _21(a21), _22(a22), _23(a23), _24(a24)
    1734             :     , _31(a31), _32(a32), _33(a33), _34(a34)
    1735             :     , _41(a41), _42(a42), _43(a43), _44(a44)
    1736           0 :     , _51(a51), _52(a52), _53(a53), _54(a54)
    1737           0 :   {}
    1738             : 
    1739             :   bool operator==(const Matrix5x4 &o) const
    1740             :   {
    1741             :     return _11 == o._11 && _12 == o._12 && _13 == o._13 && _14 == o._14 &&
    1742             :            _21 == o._21 && _22 == o._22 && _23 == o._23 && _24 == o._24 &&
    1743             :            _31 == o._31 && _32 == o._32 && _33 == o._33 && _34 == o._34 &&
    1744             :            _41 == o._41 && _42 == o._42 && _43 == o._43 && _44 == o._44 &&
    1745             :            _51 == o._51 && _52 == o._52 && _53 == o._53 && _54 == o._54;
    1746             :   }
    1747             : 
    1748             :   bool operator!=(const Matrix5x4 &aMatrix) const
    1749             :   {
    1750             :     return !(*this == aMatrix);
    1751             :   }
    1752             : 
    1753           0 :   Matrix5x4 operator*(const Matrix5x4 &aMatrix) const
    1754             :   {
    1755           0 :     Matrix5x4 resultMatrix;
    1756             : 
    1757           0 :     resultMatrix._11 = this->_11 * aMatrix._11 + this->_12 * aMatrix._21 + this->_13 * aMatrix._31 + this->_14 * aMatrix._41;
    1758           0 :     resultMatrix._12 = this->_11 * aMatrix._12 + this->_12 * aMatrix._22 + this->_13 * aMatrix._32 + this->_14 * aMatrix._42;
    1759           0 :     resultMatrix._13 = this->_11 * aMatrix._13 + this->_12 * aMatrix._23 + this->_13 * aMatrix._33 + this->_14 * aMatrix._43;
    1760           0 :     resultMatrix._14 = this->_11 * aMatrix._14 + this->_12 * aMatrix._24 + this->_13 * aMatrix._34 + this->_14 * aMatrix._44;
    1761           0 :     resultMatrix._21 = this->_21 * aMatrix._11 + this->_22 * aMatrix._21 + this->_23 * aMatrix._31 + this->_24 * aMatrix._41;
    1762           0 :     resultMatrix._22 = this->_21 * aMatrix._12 + this->_22 * aMatrix._22 + this->_23 * aMatrix._32 + this->_24 * aMatrix._42;
    1763           0 :     resultMatrix._23 = this->_21 * aMatrix._13 + this->_22 * aMatrix._23 + this->_23 * aMatrix._33 + this->_24 * aMatrix._43;
    1764           0 :     resultMatrix._24 = this->_21 * aMatrix._14 + this->_22 * aMatrix._24 + this->_23 * aMatrix._34 + this->_24 * aMatrix._44;
    1765           0 :     resultMatrix._31 = this->_31 * aMatrix._11 + this->_32 * aMatrix._21 + this->_33 * aMatrix._31 + this->_34 * aMatrix._41;
    1766           0 :     resultMatrix._32 = this->_31 * aMatrix._12 + this->_32 * aMatrix._22 + this->_33 * aMatrix._32 + this->_34 * aMatrix._42;
    1767           0 :     resultMatrix._33 = this->_31 * aMatrix._13 + this->_32 * aMatrix._23 + this->_33 * aMatrix._33 + this->_34 * aMatrix._43;
    1768           0 :     resultMatrix._34 = this->_31 * aMatrix._14 + this->_32 * aMatrix._24 + this->_33 * aMatrix._34 + this->_34 * aMatrix._44;
    1769           0 :     resultMatrix._41 = this->_41 * aMatrix._11 + this->_42 * aMatrix._21 + this->_43 * aMatrix._31 + this->_44 * aMatrix._41;
    1770           0 :     resultMatrix._42 = this->_41 * aMatrix._12 + this->_42 * aMatrix._22 + this->_43 * aMatrix._32 + this->_44 * aMatrix._42;
    1771           0 :     resultMatrix._43 = this->_41 * aMatrix._13 + this->_42 * aMatrix._23 + this->_43 * aMatrix._33 + this->_44 * aMatrix._43;
    1772           0 :     resultMatrix._44 = this->_41 * aMatrix._14 + this->_42 * aMatrix._24 + this->_43 * aMatrix._34 + this->_44 * aMatrix._44;
    1773           0 :     resultMatrix._51 = this->_51 * aMatrix._11 + this->_52 * aMatrix._21 + this->_53 * aMatrix._31 + this->_54 * aMatrix._41 + aMatrix._51;
    1774           0 :     resultMatrix._52 = this->_51 * aMatrix._12 + this->_52 * aMatrix._22 + this->_53 * aMatrix._32 + this->_54 * aMatrix._42 + aMatrix._52;
    1775           0 :     resultMatrix._53 = this->_51 * aMatrix._13 + this->_52 * aMatrix._23 + this->_53 * aMatrix._33 + this->_54 * aMatrix._43 + aMatrix._53;
    1776           0 :     resultMatrix._54 = this->_51 * aMatrix._14 + this->_52 * aMatrix._24 + this->_53 * aMatrix._34 + this->_54 * aMatrix._44 + aMatrix._54;
    1777             : 
    1778           0 :     return resultMatrix;
    1779             :   }
    1780             : 
    1781             :   Matrix5x4& operator*=(const Matrix5x4 &aMatrix)
    1782             :   {
    1783             :     *this = *this * aMatrix;
    1784             :     return *this;
    1785             :   }
    1786             : 
    1787             :   union {
    1788             :     struct {
    1789             :       Float _11, _12, _13, _14;
    1790             :       Float _21, _22, _23, _24;
    1791             :       Float _31, _32, _33, _34;
    1792             :       Float _41, _42, _43, _44;
    1793             :       Float _51, _52, _53, _54;
    1794             :     };
    1795             :     Float components[20];
    1796             :   };
    1797             : };
    1798             : 
    1799             : } // namespace gfx
    1800             : } // namespace mozilla
    1801             : 
    1802             : #endif /* MOZILLA_GFX_MATRIX_H_ */

Generated by: LCOV version 1.13