tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Matrix.h (82092B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef MOZILLA_GFX_MATRIX_H_
      8 #define MOZILLA_GFX_MATRIX_H_
      9 
     10 #include "Types.h"
     11 #include "Triangle.h"
     12 #include "Rect.h"
     13 #include "Point.h"
     14 #include "Quaternion.h"
     15 #include <iosfwd>
     16 #include <math.h>
     17 #include "mozilla/Attributes.h"
     18 #include "mozilla/DebugOnly.h"
     19 #include "mozilla/FloatingPoint.h"
     20 #include "mozilla/gfx/ScaleFactors2D.h"
     21 #include "mozilla/Span.h"
     22 
     23 namespace mozilla {
     24 namespace gfx {
     25 
     26 static inline bool FuzzyEqual(Float aV1, Float aV2) {
     27  // XXX - Check if fabs does the smart thing and just negates the sign bit.
     28  return fabs(aV2 - aV1) < 1e-6;
     29 }
     30 
     31 template <typename F>
     32 Span<Point4DTyped<UnknownUnits, F>> IntersectPolygon(
     33    Span<Point4DTyped<UnknownUnits, F>> aPoints,
     34    const Point4DTyped<UnknownUnits, F>& aPlaneNormal,
     35    Span<Point4DTyped<UnknownUnits, F>> aDestBuffer);
     36 
     37 template <class T>
     38 using BaseMatrixScales = BaseScaleFactors2D<UnknownUnits, UnknownUnits, T>;
     39 
     40 using MatrixScales = BaseMatrixScales<float>;
     41 using MatrixScalesDouble = BaseMatrixScales<double>;
     42 
     43 template <class T>
     44 class BaseMatrix {
     45  // Alias that maps to either Point or PointDouble depending on whether T is a
     46  // float or a double.
     47  typedef PointTyped<UnknownUnits, T> MatrixPoint;
     48  // Same for size and rect
     49  typedef SizeTyped<UnknownUnits, T> MatrixSize;
     50  typedef RectTyped<UnknownUnits, T> MatrixRect;
     51 
     52 public:
     53  BaseMatrix() : _11(1.0f), _12(0), _21(0), _22(1.0f), _31(0), _32(0) {}
     54  BaseMatrix(T a11, T a12, T a21, T a22, T a31, T a32)
     55      : _11(a11), _12(a12), _21(a21), _22(a22), _31(a31), _32(a32) {}
     56  union {
     57    struct {
     58      T _11, _12;
     59      T _21, _22;
     60      T _31, _32;
     61    };
     62    T components[6];
     63  };
     64 
     65  template <class T2>
     66  explicit BaseMatrix(const BaseMatrix<T2>& aOther)
     67      : _11(aOther._11),
     68        _12(aOther._12),
     69        _21(aOther._21),
     70        _22(aOther._22),
     71        _31(aOther._31),
     72        _32(aOther._32) {}
     73 
     74  MOZ_ALWAYS_INLINE BaseMatrix Copy() const { return BaseMatrix<T>(*this); }
     75 
     76  friend std::ostream& operator<<(std::ostream& aStream,
     77                                  const BaseMatrix& aMatrix) {
     78    if (aMatrix.IsIdentity()) {
     79      return aStream << "[ I ]";
     80    }
     81    return aStream << "[ " << aMatrix._11 << " " << aMatrix._12 << "; "
     82                   << aMatrix._21 << " " << aMatrix._22 << "; " << aMatrix._31
     83                   << " " << aMatrix._32 << "; ]";
     84  }
     85 
     86  MatrixPoint TransformPoint(const MatrixPoint& aPoint) const {
     87    MatrixPoint retPoint;
     88 
     89    retPoint.x = aPoint.x * _11 + aPoint.y * _21 + _31;
     90    retPoint.y = aPoint.x * _12 + aPoint.y * _22 + _32;
     91 
     92    return retPoint;
     93  }
     94 
     95  MatrixSize TransformSize(const MatrixSize& aSize) const {
     96    MatrixSize retSize;
     97 
     98    retSize.width = aSize.width * _11 + aSize.height * _21;
     99    retSize.height = aSize.width * _12 + aSize.height * _22;
    100 
    101    return retSize;
    102  }
    103 
    104  /**
    105   * In most cases you probably want to use TransformBounds. This function
    106   * just transforms the top-left and size separately and constructs a rect
    107   * from those results.
    108   */
    109  MatrixRect TransformRect(const MatrixRect& aRect) const {
    110    return MatrixRect(TransformPoint(aRect.TopLeft()),
    111                      TransformSize(aRect.Size()));
    112  }
    113 
    114  GFX2D_API MatrixRect TransformBounds(const MatrixRect& aRect) const {
    115    int i;
    116    MatrixPoint quad[4];
    117    T min_x, max_x;
    118    T min_y, max_y;
    119 
    120    quad[0] = TransformPoint(aRect.TopLeft());
    121    quad[1] = TransformPoint(aRect.TopRight());
    122    quad[2] = TransformPoint(aRect.BottomLeft());
    123    quad[3] = TransformPoint(aRect.BottomRight());
    124 
    125    min_x = max_x = quad[0].x;
    126    min_y = max_y = quad[0].y;
    127 
    128    for (i = 1; i < 4; i++) {
    129      if (quad[i].x < min_x) min_x = quad[i].x;
    130      if (quad[i].x > max_x) max_x = quad[i].x;
    131 
    132      if (quad[i].y < min_y) min_y = quad[i].y;
    133      if (quad[i].y > max_y) max_y = quad[i].y;
    134    }
    135 
    136    return MatrixRect(min_x, min_y, max_x - min_x, max_y - min_y);
    137  }
    138 
    139  static BaseMatrix<T> Translation(T aX, T aY) {
    140    return BaseMatrix<T>(1.0f, 0.0f, 0.0f, 1.0f, aX, aY);
    141  }
    142 
    143  static BaseMatrix<T> Translation(MatrixPoint aPoint) {
    144    return Translation(aPoint.x, aPoint.y);
    145  }
    146 
    147  /**
    148   * Apply a translation to this matrix.
    149   *
    150   * The "Pre" in this method's name means that the translation is applied
    151   * -before- this matrix's existing transformation. That is, any vector that
    152   * is multiplied by the resulting matrix will first be translated, then be
    153   * transformed by the original transform.
    154   *
    155   * Calling this method will result in this matrix having the same value as
    156   * the result of:
    157   *
    158   *   BaseMatrix<T>::Translation(x, y) * this
    159   *
    160   * (Note that in performance critical code multiplying by the result of a
    161   * Translation()/Scaling() call is not recommended since that results in a
    162   * full matrix multiply involving 12 floating-point multiplications. Calling
    163   * this method would be preferred since it only involves four floating-point
    164   * multiplications.)
    165   */
    166  BaseMatrix<T>& PreTranslate(T aX, T aY) {
    167    _31 += _11 * aX + _21 * aY;
    168    _32 += _12 * aX + _22 * aY;
    169 
    170    return *this;
    171  }
    172 
    173  BaseMatrix<T>& PreTranslate(const MatrixPoint& aPoint) {
    174    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  BaseMatrix<T>& PostTranslate(T aX, T aY) {
    190    _31 += aX;
    191    _32 += aY;
    192    return *this;
    193  }
    194 
    195  BaseMatrix<T>& PostTranslate(const MatrixPoint& aPoint) {
    196    return PostTranslate(aPoint.x, aPoint.y);
    197  }
    198 
    199  static BaseMatrix<T> Scaling(T aScaleX, T aScaleY) {
    200    return BaseMatrix<T>(aScaleX, 0.0f, 0.0f, aScaleY, 0.0f, 0.0f);
    201  }
    202 
    203  static BaseMatrix<T> Scaling(const BaseMatrixScales<T>& scale) {
    204    return Scaling(scale.xScale, scale.yScale);
    205  }
    206 
    207  /**
    208   * Similar to PreTranslate, but applies a scale instead of a translation.
    209   */
    210  BaseMatrix<T>& PreScale(T aX, T aY) {
    211    _11 *= aX;
    212    _12 *= aX;
    213    _21 *= aY;
    214    _22 *= aY;
    215 
    216    return *this;
    217  }
    218 
    219  BaseMatrix<T>& PreScale(const BaseMatrixScales<T>& scale) {
    220    return PreScale(scale.xScale, scale.yScale);
    221  }
    222 
    223  /**
    224   * Similar to PostTranslate, but applies a scale instead of a translation.
    225   */
    226  BaseMatrix<T>& PostScale(T aScaleX, T aScaleY) {
    227    _11 *= aScaleX;
    228    _12 *= aScaleY;
    229    _21 *= aScaleX;
    230    _22 *= aScaleY;
    231    _31 *= aScaleX;
    232    _32 *= aScaleY;
    233 
    234    return *this;
    235  }
    236 
    237  GFX2D_API static BaseMatrix<T> Rotation(T aAngle);
    238 
    239  /**
    240   * Similar to PreTranslate, but applies a rotation instead of a translation.
    241   */
    242  BaseMatrix<T>& PreRotate(T aAngle) {
    243    return *this = BaseMatrix<T>::Rotation(aAngle) * *this;
    244  }
    245 
    246  bool Invert() {
    247    // Compute co-factors.
    248    T A = _22;
    249    T B = -_21;
    250    T C = _21 * _32 - _22 * _31;
    251    T D = -_12;
    252    T E = _11;
    253    T F = _31 * _12 - _11 * _32;
    254 
    255    T det = Determinant();
    256 
    257    if (!det) {
    258      return false;
    259    }
    260 
    261    T inv_det = 1 / det;
    262 
    263    _11 = inv_det * A;
    264    _12 = inv_det * D;
    265    _21 = inv_det * B;
    266    _22 = inv_det * E;
    267    _31 = inv_det * C;
    268    _32 = inv_det * F;
    269 
    270    return true;
    271  }
    272 
    273  BaseMatrix<T> Inverse() const {
    274    BaseMatrix<T> clone = *this;
    275    DebugOnly<bool> inverted = clone.Invert();
    276    MOZ_ASSERT(inverted,
    277               "Attempted to get the inverse of a non-invertible matrix");
    278    return clone;
    279  }
    280 
    281  T Determinant() const { return _11 * _22 - _12 * _21; }
    282 
    283  BaseMatrix<T> operator*(const BaseMatrix<T>& aMatrix) const {
    284    BaseMatrix<T> resultMatrix;
    285 
    286    resultMatrix._11 = this->_11 * aMatrix._11 + this->_12 * aMatrix._21;
    287    resultMatrix._12 = this->_11 * aMatrix._12 + this->_12 * aMatrix._22;
    288    resultMatrix._21 = this->_21 * aMatrix._11 + this->_22 * aMatrix._21;
    289    resultMatrix._22 = this->_21 * aMatrix._12 + this->_22 * aMatrix._22;
    290    resultMatrix._31 =
    291        this->_31 * aMatrix._11 + this->_32 * aMatrix._21 + aMatrix._31;
    292    resultMatrix._32 =
    293        this->_31 * aMatrix._12 + this->_32 * aMatrix._22 + aMatrix._32;
    294 
    295    return resultMatrix;
    296  }
    297 
    298  BaseMatrix<T>& operator*=(const BaseMatrix<T>& aMatrix) {
    299    *this = *this * aMatrix;
    300    return *this;
    301  }
    302 
    303  /**
    304   * Multiplies *this with aMatrix and returns the result.
    305   */
    306  Matrix4x4 operator*(const Matrix4x4& aMatrix) const;
    307 
    308  /**
    309   * Multiplies in the opposite order to operator=*.
    310   */
    311  BaseMatrix<T>& PreMultiply(const BaseMatrix<T>& aMatrix) {
    312    *this = aMatrix * *this;
    313    return *this;
    314  }
    315 
    316  /**
    317   * Please explicitly use either FuzzyEquals or ExactlyEquals.
    318   */
    319  bool operator==(const BaseMatrix<T>& other) const = delete;
    320  bool operator!=(const BaseMatrix<T>& other) const = delete;
    321 
    322  /* Returns true if the other matrix is fuzzy-equal to this matrix.
    323   * Note that this isn't a cheap comparison!
    324   */
    325  bool FuzzyEquals(const BaseMatrix<T>& o) const {
    326    return FuzzyEqual(_11, o._11) && FuzzyEqual(_12, o._12) &&
    327           FuzzyEqual(_21, o._21) && FuzzyEqual(_22, o._22) &&
    328           FuzzyEqual(_31, o._31) && FuzzyEqual(_32, o._32);
    329  }
    330 
    331  bool ExactlyEquals(const BaseMatrix<T>& o) const {
    332    return _11 == o._11 && _12 == o._12 && _21 == o._21 && _22 == o._22 &&
    333           _31 == o._31 && _32 == o._32;
    334  }
    335 
    336  /* Verifies that the matrix contains no Infs or NaNs. */
    337  bool IsFinite() const {
    338    return std::isfinite(_11) && std::isfinite(_12) && std::isfinite(_21) &&
    339           std::isfinite(_22) && std::isfinite(_31) && std::isfinite(_32);
    340  }
    341 
    342  /* Returns true if the matrix is a rectilinear transformation (i.e.
    343   * grid-aligned rectangles are transformed to grid-aligned rectangles)
    344   */
    345  bool IsRectilinear() const {
    346    if (FuzzyEqual(_12, 0) && FuzzyEqual(_21, 0)) {
    347      return true;
    348    } else if (FuzzyEqual(_22, 0) && FuzzyEqual(_11, 0)) {
    349      return true;
    350    }
    351 
    352    return false;
    353  }
    354 
    355  /**
    356   * Returns true if the matrix is anything other than a straight
    357   * translation by integers.
    358   */
    359  bool HasNonIntegerTranslation() const {
    360    return HasNonTranslation() || !FuzzyEqual(_31, floor(_31 + 0.5f)) ||
    361           !FuzzyEqual(_32, floor(_32 + 0.5f));
    362  }
    363 
    364  /**
    365   * Returns true if the matrix only has an integer translation.
    366   */
    367  bool HasOnlyIntegerTranslation() const { return !HasNonIntegerTranslation(); }
    368 
    369  /**
    370   * Returns true if the matrix has any transform other
    371   * than a straight translation.
    372   */
    373  bool HasNonTranslation() const {
    374    return !FuzzyEqual(_11, 1.0) || !FuzzyEqual(_22, 1.0) ||
    375           !FuzzyEqual(_12, 0.0) || !FuzzyEqual(_21, 0.0);
    376  }
    377 
    378  /**
    379   * Returns true if the matrix has any transform other
    380   * than a translation or a -1 y scale (y axis flip)
    381   */
    382  bool HasNonTranslationOrFlip() const {
    383    return !FuzzyEqual(_11, 1.0) ||
    384           (!FuzzyEqual(_22, 1.0) && !FuzzyEqual(_22, -1.0)) ||
    385           !FuzzyEqual(_21, 0.0) || !FuzzyEqual(_12, 0.0);
    386  }
    387 
    388  /* Returns true if the matrix is an identity matrix.
    389   */
    390  bool IsIdentity() const {
    391    return _11 == 1.0f && _12 == 0.0f && _21 == 0.0f && _22 == 1.0f &&
    392           _31 == 0.0f && _32 == 0.0f;
    393  }
    394 
    395  /* Returns true if the matrix is singular.
    396   */
    397  bool IsSingular() const {
    398    T det = Determinant();
    399    return !std::isfinite(det) || det == 0;
    400  }
    401 
    402  GFX2D_API BaseMatrix<T>& NudgeToIntegers() {
    403    NudgeToInteger(&_11);
    404    NudgeToInteger(&_12);
    405    NudgeToInteger(&_21);
    406    NudgeToInteger(&_22);
    407    NudgeToInteger(&_31);
    408    NudgeToInteger(&_32);
    409    return *this;
    410  }
    411 
    412  bool IsTranslation() const {
    413    return FuzzyEqual(_11, 1.0f) && FuzzyEqual(_12, 0.0f) &&
    414           FuzzyEqual(_21, 0.0f) && FuzzyEqual(_22, 1.0f);
    415  }
    416 
    417  static bool FuzzyIsInteger(T aValue) {
    418    return FuzzyEqual(aValue, floorf(aValue + 0.5f));
    419  }
    420 
    421  bool IsIntegerTranslation() const {
    422    return IsTranslation() && FuzzyIsInteger(_31) && FuzzyIsInteger(_32);
    423  }
    424 
    425  bool IsAllIntegers() const {
    426    return FuzzyIsInteger(_11) && FuzzyIsInteger(_12) && FuzzyIsInteger(_21) &&
    427           FuzzyIsInteger(_22) && FuzzyIsInteger(_31) && FuzzyIsInteger(_32);
    428  }
    429 
    430  MatrixPoint GetTranslation() const { return MatrixPoint(_31, _32); }
    431 
    432  /**
    433   * Returns true if matrix is multiple of 90 degrees rotation with flipping,
    434   * scaling and translation.
    435   */
    436  bool PreservesAxisAlignedRectangles() const {
    437    return ((FuzzyEqual(_11, 0.0) && FuzzyEqual(_22, 0.0)) ||
    438            (FuzzyEqual(_12, 0.0) && FuzzyEqual(_21, 0.0)));
    439  }
    440 
    441  /**
    442   * Returns true if the matrix has any transform other
    443   * than a translation or scale; this is, if there is
    444   * rotation.
    445   */
    446  bool HasNonAxisAlignedTransform() const {
    447    return !FuzzyEqual(_21, 0.0) || !FuzzyEqual(_12, 0.0);
    448  }
    449 
    450  /**
    451   * Returns true if the matrix has negative scaling (i.e. flip).
    452   */
    453  bool HasNegativeScaling() const { return (_11 < 0.0) || (_22 < 0.0); }
    454 
    455  /**
    456   * Computes the scale factors of this matrix; that is,
    457   * the amounts each basis vector is scaled by.
    458   */
    459  BaseMatrixScales<T> ScaleFactors() const {
    460    T det = Determinant();
    461 
    462    if (det == 0.0) {
    463      return BaseMatrixScales<T>(0.0, 0.0);
    464    }
    465 
    466    MatrixSize sz = MatrixSize(1.0, 0.0);
    467    sz = TransformSize(sz);
    468 
    469    T major = sqrt(sz.width * sz.width + sz.height * sz.height);
    470    T minor = 0.0;
    471 
    472    // ignore mirroring
    473    if (det < 0.0) {
    474      det = -det;
    475    }
    476 
    477    if (major) {
    478      minor = det / major;
    479    }
    480 
    481    return BaseMatrixScales<T>(major, minor);
    482  }
    483 
    484  /**
    485   * Returns true if the matrix preserves distances, i.e. a rigid transformation
    486   * that doesn't change size or shape). Such a matrix has uniform unit scaling
    487   * and an orthogonal basis.
    488   */
    489  bool PreservesDistance() const {
    490    return FuzzyEqual(_11 * _11 + _12 * _12, 1.0) &&
    491           FuzzyEqual(_21 * _21 + _22 * _22, 1.0) &&
    492           FuzzyEqual(_11 * _21 + _12 * _22, 0.0);
    493  }
    494 };
    495 
    496 typedef BaseMatrix<Float> Matrix;
    497 typedef BaseMatrix<Double> MatrixDouble;
    498 
    499 // Helper functions used by Matrix4x4Typed defined in Matrix.cpp
    500 double SafeTangent(double aTheta);
    501 double FlushToZero(double aVal);
    502 
    503 template <class Units, class F>
    504 Point4DTyped<Units, F> ComputePerspectivePlaneIntercept(
    505    const Point4DTyped<Units, F>& aFirst,
    506    const Point4DTyped<Units, F>& aSecond) {
    507  // This function will always return a point with a w value of 0.
    508  // The X, Y, and Z components will point towards an infinite vanishing
    509  // point.
    510 
    511  // We want to interpolate aFirst and aSecond to find the point intersecting
    512  // with the w=0 plane.
    513 
    514  // Since we know what we want the w component to be, we can rearrange the
    515  // interpolation equation and solve for t.
    516  float t = -aFirst.w / (aSecond.w - aFirst.w);
    517 
    518  // Use t to find the remainder of the components
    519  return aFirst + (aSecond - aFirst) * t;
    520 }
    521 
    522 template <class SourceUnits, class TargetUnits, class T>
    523 class Matrix4x4Typed {
    524 public:
    525  typedef PointTyped<SourceUnits, T> SourcePoint;
    526  typedef PointTyped<TargetUnits, T> TargetPoint;
    527  typedef Point3DTyped<SourceUnits, T> SourcePoint3D;
    528  typedef Point3DTyped<TargetUnits, T> TargetPoint3D;
    529  typedef Point4DTyped<SourceUnits, T> SourcePoint4D;
    530  typedef Point4DTyped<TargetUnits, T> TargetPoint4D;
    531  typedef RectTyped<SourceUnits, T> SourceRect;
    532  typedef RectTyped<TargetUnits, T> TargetRect;
    533 
    534  Matrix4x4Typed()
    535      : _11(1.0f),
    536        _12(0.0f),
    537        _13(0.0f),
    538        _14(0.0f),
    539        _21(0.0f),
    540        _22(1.0f),
    541        _23(0.0f),
    542        _24(0.0f),
    543        _31(0.0f),
    544        _32(0.0f),
    545        _33(1.0f),
    546        _34(0.0f),
    547        _41(0.0f),
    548        _42(0.0f),
    549        _43(0.0f),
    550        _44(1.0f) {}
    551 
    552  Matrix4x4Typed(T a11, T a12, T a13, T a14, T a21, T a22, T a23, T a24, T a31,
    553                 T a32, T a33, T a34, T a41, T a42, T a43, T a44)
    554      : _11(a11),
    555        _12(a12),
    556        _13(a13),
    557        _14(a14),
    558        _21(a21),
    559        _22(a22),
    560        _23(a23),
    561        _24(a24),
    562        _31(a31),
    563        _32(a32),
    564        _33(a33),
    565        _34(a34),
    566        _41(a41),
    567        _42(a42),
    568        _43(a43),
    569        _44(a44) {}
    570 
    571  explicit Matrix4x4Typed(const T aArray[16]) {
    572    memcpy(components, aArray, sizeof(components));
    573  }
    574 
    575  Matrix4x4Typed(const Matrix4x4Typed& aOther) {
    576    memcpy(components, aOther.components, sizeof(components));
    577  }
    578 
    579  template <class T2>
    580  explicit Matrix4x4Typed(
    581      const Matrix4x4Typed<SourceUnits, TargetUnits, T2>& aOther)
    582      : _11(aOther._11),
    583        _12(aOther._12),
    584        _13(aOther._13),
    585        _14(aOther._14),
    586        _21(aOther._21),
    587        _22(aOther._22),
    588        _23(aOther._23),
    589        _24(aOther._24),
    590        _31(aOther._31),
    591        _32(aOther._32),
    592        _33(aOther._33),
    593        _34(aOther._34),
    594        _41(aOther._41),
    595        _42(aOther._42),
    596        _43(aOther._43),
    597        _44(aOther._44) {}
    598 
    599  union {
    600    struct {
    601      T _11, _12, _13, _14;
    602      T _21, _22, _23, _24;
    603      T _31, _32, _33, _34;
    604      T _41, _42, _43, _44;
    605    };
    606    T components[16];
    607  };
    608 
    609  friend std::ostream& operator<<(std::ostream& aStream,
    610                                  const Matrix4x4Typed& aMatrix) {
    611    if (aMatrix.Is2D()) {
    612      BaseMatrix<T> matrix = aMatrix.As2D();
    613      return aStream << matrix;
    614    }
    615    const T* f = &aMatrix._11;
    616    aStream << "[ " << f[0] << ' ' << f[1] << ' ' << f[2] << ' ' << f[3] << ';';
    617    f += 4;
    618    aStream << ' ' << f[0] << ' ' << f[1] << ' ' << f[2] << ' ' << f[3] << ';';
    619    f += 4;
    620    aStream << ' ' << f[0] << ' ' << f[1] << ' ' << f[2] << ' ' << f[3] << ';';
    621    f += 4;
    622    aStream << ' ' << f[0] << ' ' << f[1] << ' ' << f[2] << ' ' << f[3]
    623            << "; ]";
    624    return aStream;
    625  }
    626 
    627  Point4DTyped<UnknownUnits, T>& operator[](int aIndex) {
    628    MOZ_ASSERT(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index");
    629    return *reinterpret_cast<Point4DTyped<UnknownUnits, T>*>((&_11) +
    630                                                             4 * aIndex);
    631  }
    632  const Point4DTyped<UnknownUnits, T>& operator[](int aIndex) const {
    633    MOZ_ASSERT(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index");
    634    return *reinterpret_cast<const Point4DTyped<UnknownUnits, T>*>((&_11) +
    635                                                                   4 * aIndex);
    636  }
    637 
    638  // External code should avoid calling this, and instead use
    639  // ViewAs() from UnitTransforms.h, which requires providing
    640  // a justification.
    641  template <typename NewMatrix4x4Typed>
    642  [[nodiscard]] NewMatrix4x4Typed Cast() const {
    643    return NewMatrix4x4Typed(_11, _12, _13, _14, _21, _22, _23, _24, _31, _32,
    644                             _33, _34, _41, _42, _43, _44);
    645  }
    646 
    647  /**
    648   * Returns true if the matrix is isomorphic to a 2D affine transformation.
    649   */
    650  bool Is2D() const {
    651    if (_13 != 0.0f || _14 != 0.0f || _23 != 0.0f || _24 != 0.0f ||
    652        _31 != 0.0f || _32 != 0.0f || _33 != 1.0f || _34 != 0.0f ||
    653        _43 != 0.0f || _44 != 1.0f) {
    654      return false;
    655    }
    656    return true;
    657  }
    658 
    659  bool Is2D(BaseMatrix<T>* aMatrix) const {
    660    if (!Is2D()) {
    661      return false;
    662    }
    663    if (aMatrix) {
    664      aMatrix->_11 = _11;
    665      aMatrix->_12 = _12;
    666      aMatrix->_21 = _21;
    667      aMatrix->_22 = _22;
    668      aMatrix->_31 = _41;
    669      aMatrix->_32 = _42;
    670    }
    671    return true;
    672  }
    673 
    674  BaseMatrix<T> As2D() const {
    675    MOZ_ASSERT(Is2D(), "Matrix is not a 2D affine transform");
    676 
    677    return BaseMatrix<T>(_11, _12, _21, _22, _41, _42);
    678  }
    679 
    680  bool CanDraw2D(BaseMatrix<T>* aMatrix = nullptr) const {
    681    if (_14 != 0.0f || _24 != 0.0f || _44 != 1.0f) {
    682      return false;
    683    }
    684    if (aMatrix) {
    685      aMatrix->_11 = _11;
    686      aMatrix->_12 = _12;
    687      aMatrix->_21 = _21;
    688      aMatrix->_22 = _22;
    689      aMatrix->_31 = _41;
    690      aMatrix->_32 = _42;
    691    }
    692    return true;
    693  }
    694 
    695  Matrix4x4Typed& ProjectTo2D() {
    696    _31 = 0.0f;
    697    _32 = 0.0f;
    698    _13 = 0.0f;
    699    _23 = 0.0f;
    700    _33 = 1.0f;
    701    _43 = 0.0f;
    702    _34 = 0.0f;
    703    // Some matrices, such as those derived from perspective transforms,
    704    // can modify _44 from 1, while leaving the rest of the fourth column
    705    // (_14, _24) at 0. In this case, after resetting the third row and
    706    // third column above, the value of _44 functions only to scale the
    707    // coordinate transform divide by W. The matrix can be converted to
    708    // a true 2D matrix by normalizing out the scaling effect of _44 on
    709    // the remaining components ahead of time.
    710    if (_14 == 0.0f && _24 == 0.0f && _44 != 1.0f && _44 != 0.0f) {
    711      T scale = 1.0f / _44;
    712      _11 *= scale;
    713      _12 *= scale;
    714      _21 *= scale;
    715      _22 *= scale;
    716      _41 *= scale;
    717      _42 *= scale;
    718      _44 = 1.0f;
    719    }
    720    return *this;
    721  }
    722 
    723  template <class F>
    724  Point4DTyped<TargetUnits, F> ProjectPoint(
    725      const PointTyped<SourceUnits, F>& aPoint) const {
    726    // Find a value for z that will transform to 0.
    727 
    728    // The transformed value of z is computed as:
    729    // z' = aPoint.x * _13 + aPoint.y * _23 + z * _33 + _43;
    730 
    731    // Solving for z when z' = 0 gives us:
    732    F z = -(aPoint.x * _13 + aPoint.y * _23 + _43) / _33;
    733 
    734    // Compute the transformed point
    735    return this->TransformPoint(
    736        Point4DTyped<SourceUnits, F>(aPoint.x, aPoint.y, z, 1));
    737  }
    738 
    739  template <class F>
    740  RectTyped<TargetUnits, F> ProjectRectBounds(
    741      const RectTyped<SourceUnits, F>& aRect,
    742      const RectTyped<TargetUnits, F>& aClip) const {
    743    // This function must never return std::numeric_limits<Float>::max() or any
    744    // other arbitrary large value in place of inifinity.  This often occurs
    745    // when aRect is an inversed projection matrix or when aRect is transformed
    746    // to be partly behind and in front of the camera (w=0 plane in homogenous
    747    // coordinates) - See Bug 1035611
    748 
    749    // Some call-sites will call RoundGfxRectToAppRect which clips both the
    750    // extents and dimensions of the rect to be bounded by nscoord_MAX.
    751    // If we return a Rect that, when converted to nscoords, has a width or
    752    // height greater than nscoord_MAX, RoundGfxRectToAppRect will clip the
    753    // overflow off both the min and max end of the rect after clipping the
    754    // extents of the rect, resulting in a translation of the rect towards the
    755    // infinite end.
    756 
    757    // The bounds returned by ProjectRectBounds are expected to be clipped only
    758    // on the edges beyond the bounds of the coordinate system; otherwise, the
    759    // clipped bounding box would be smaller than the correct one and result
    760    // bugs such as incorrect culling (eg. Bug 1073056)
    761 
    762    // To address this without requiring all code to work in homogenous
    763    // coordinates or interpret infinite values correctly, a specialized
    764    // clipping function is integrated into ProjectRectBounds.
    765 
    766    // Callers should pass an aClip value that represents the extents to clip
    767    // the result to, in the same coordinate system as aRect.
    768    Point4DTyped<TargetUnits, F> points[4];
    769 
    770    points[0] = ProjectPoint(aRect.TopLeft());
    771    points[1] = ProjectPoint(aRect.TopRight());
    772    points[2] = ProjectPoint(aRect.BottomRight());
    773    points[3] = ProjectPoint(aRect.BottomLeft());
    774 
    775    F min_x = std::numeric_limits<F>::max();
    776    F min_y = std::numeric_limits<F>::max();
    777    F max_x = -std::numeric_limits<F>::max();
    778    F max_y = -std::numeric_limits<F>::max();
    779 
    780    for (int i = 0; i < 4; i++) {
    781      // Only use points that exist above the w=0 plane
    782      if (points[i].HasPositiveWCoord()) {
    783        PointTyped<TargetUnits, F> point2d =
    784            aClip.ClampPoint(points[i].As2DPoint());
    785        min_x = std::min<F>(point2d.x, min_x);
    786        max_x = std::max<F>(point2d.x, max_x);
    787        min_y = std::min<F>(point2d.y, min_y);
    788        max_y = std::max<F>(point2d.y, max_y);
    789      }
    790 
    791      int next = (i == 3) ? 0 : i + 1;
    792      if (points[i].HasPositiveWCoord() != points[next].HasPositiveWCoord()) {
    793        // If the line between two points crosses the w=0 plane, then
    794        // interpolate to find the point of intersection with the w=0 plane and
    795        // use that instead.
    796        Point4DTyped<TargetUnits, F> intercept =
    797            ComputePerspectivePlaneIntercept(points[i], points[next]);
    798        // Since intercept.w will always be 0 here, we interpret x,y,z as a
    799        // direction towards an infinite vanishing point.
    800        if (intercept.x < 0.0f) {
    801          min_x = aClip.X();
    802        } else if (intercept.x > 0.0f) {
    803          max_x = aClip.XMost();
    804        }
    805        if (intercept.y < 0.0f) {
    806          min_y = aClip.Y();
    807        } else if (intercept.y > 0.0f) {
    808          max_y = aClip.YMost();
    809        }
    810      }
    811    }
    812 
    813    if (max_x < min_x || max_y < min_y) {
    814      return RectTyped<TargetUnits, F>(0, 0, 0, 0);
    815    }
    816 
    817    return RectTyped<TargetUnits, F>(min_x, min_y, max_x - min_x,
    818                                     max_y - min_y);
    819  }
    820 
    821  /**
    822   * TransformAndClipBounds transforms aRect as a bounding box, while clipping
    823   * the transformed bounds to the extents of aClip.
    824   */
    825  template <class F>
    826  RectTyped<TargetUnits, F> TransformAndClipBounds(
    827      const RectTyped<SourceUnits, F>& aRect,
    828      const RectTyped<TargetUnits, F>& aClip) const {
    829    PointTyped<UnknownUnits, F> verts[kTransformAndClipRectMaxVerts];
    830    size_t vertCount = TransformAndClipRect(aRect, aClip, verts);
    831 
    832    F min_x = std::numeric_limits<F>::max();
    833    F min_y = std::numeric_limits<F>::max();
    834    F max_x = -std::numeric_limits<F>::max();
    835    F max_y = -std::numeric_limits<F>::max();
    836    for (size_t i = 0; i < vertCount; i++) {
    837      min_x = std::min(min_x, verts[i].x.value);
    838      max_x = std::max(max_x, verts[i].x.value);
    839      min_y = std::min(min_y, verts[i].y.value);
    840      max_y = std::max(max_y, verts[i].y.value);
    841    }
    842 
    843    if (max_x < min_x || max_y < min_y) {
    844      return RectTyped<TargetUnits, F>(0, 0, 0, 0);
    845    }
    846 
    847    return RectTyped<TargetUnits, F>(min_x, min_y, max_x - min_x,
    848                                     max_y - min_y);
    849  }
    850 
    851  template <class F>
    852  RectTyped<TargetUnits, F> TransformAndClipBounds(
    853      const TriangleTyped<SourceUnits, F>& aTriangle,
    854      const RectTyped<TargetUnits, F>& aClip) const {
    855    return TransformAndClipBounds(aTriangle.BoundingBox(), aClip);
    856  }
    857 
    858  /**
    859   * TransformAndClipRect projects a rectangle and clips against view frustum
    860   * clipping planes in homogenous space so that its projected vertices are
    861   * constrained within the 2d rectangle passed in aClip.
    862   * The resulting vertices are populated in aVerts.  aVerts must be
    863   * pre-allocated to hold at least kTransformAndClipRectMaxVerts Points.
    864   * The vertex count is returned by TransformAndClipRect.  It is possible to
    865   * emit fewer than 3 vertices, indicating that aRect will not be visible
    866   * within aClip.
    867   */
    868  template <class F>
    869  size_t TransformAndClipRect(const RectTyped<SourceUnits, F>& aRect,
    870                              const RectTyped<TargetUnits, F>& aClip,
    871                              PointTyped<TargetUnits, F>* aVerts) const {
    872    typedef Point4DTyped<UnknownUnits, F> P4D;
    873 
    874    // The initial polygon is made up by the corners of aRect in homogenous
    875    // space, mapped into the destination space of this transform.
    876    P4D rectCorners[] = {
    877        TransformPoint(P4D(aRect.X(), aRect.Y(), 0, 1)),
    878        TransformPoint(P4D(aRect.XMost(), aRect.Y(), 0, 1)),
    879        TransformPoint(P4D(aRect.XMost(), aRect.YMost(), 0, 1)),
    880        TransformPoint(P4D(aRect.X(), aRect.YMost(), 0, 1)),
    881    };
    882 
    883    // Cut off pieces of the polygon that are outside of aClip (the "view
    884    // frustrum"), by consecutively intersecting the polygon with the half space
    885    // induced by the clipping plane for each side of aClip.
    886    // View frustum clipping planes are described as normals originating from
    887    // the 0,0,0,0 origin.
    888    // Each pass can increase or decrease the number of points that make up the
    889    // current clipped polygon. We double buffer the set of points, alternating
    890    // between polygonBufA and polygonBufB. Duplicated points in the polygons
    891    // are kept around until all clipping is done. The loop at the end filters
    892    // out any consecutive duplicates.
    893    P4D polygonBufA[kTransformAndClipRectMaxVerts];
    894    P4D polygonBufB[kTransformAndClipRectMaxVerts];
    895 
    896    Span<P4D> polygon(rectCorners);
    897    polygon = IntersectPolygon<F>(polygon, P4D(1.0, 0.0, 0.0, -aClip.X()),
    898                                  polygonBufA);
    899    polygon = IntersectPolygon<F>(polygon, P4D(-1.0, 0.0, 0.0, aClip.XMost()),
    900                                  polygonBufB);
    901    polygon = IntersectPolygon<F>(polygon, P4D(0.0, 1.0, 0.0, -aClip.Y()),
    902                                  polygonBufA);
    903    polygon = IntersectPolygon<F>(polygon, P4D(0.0, -1.0, 0.0, aClip.YMost()),
    904                                  polygonBufB);
    905 
    906    size_t vertCount = 0;
    907    for (const auto& srcPoint : polygon) {
    908      PointTyped<TargetUnits, F> p;
    909      if (srcPoint.w == 0.0) {
    910        // If a point lies on the intersection of the clipping planes at
    911        // (0,0,0,0), we must avoid a division by zero w component.
    912        p = PointTyped<TargetUnits, F>(0.0, 0.0);
    913      } else {
    914        p = srcPoint.As2DPoint();
    915      }
    916      // Emit only unique points
    917      if (vertCount == 0 || p != aVerts[vertCount - 1]) {
    918        aVerts[vertCount++] = p;
    919      }
    920    }
    921 
    922    return vertCount;
    923  }
    924 
    925  static const int kTransformAndClipRectMaxVerts = 32;
    926 
    927  static Matrix4x4Typed From2D(const BaseMatrix<T>& aMatrix) {
    928    Matrix4x4Typed matrix;
    929    matrix._11 = aMatrix._11;
    930    matrix._12 = aMatrix._12;
    931    matrix._21 = aMatrix._21;
    932    matrix._22 = aMatrix._22;
    933    matrix._41 = aMatrix._31;
    934    matrix._42 = aMatrix._32;
    935    return matrix;
    936  }
    937 
    938  bool Is2DIntegerTranslation() const {
    939    return Is2D() && As2D().IsIntegerTranslation();
    940  }
    941 
    942  TargetPoint4D TransposeTransform4D(const SourcePoint4D& aPoint) const {
    943    Float x = aPoint.x * _11 + aPoint.y * _12 + aPoint.z * _13 + aPoint.w * _14;
    944    Float y = aPoint.x * _21 + aPoint.y * _22 + aPoint.z * _23 + aPoint.w * _24;
    945    Float z = aPoint.x * _31 + aPoint.y * _32 + aPoint.z * _33 + aPoint.w * _34;
    946    Float w = aPoint.x * _41 + aPoint.y * _42 + aPoint.z * _43 + aPoint.w * _44;
    947 
    948    return TargetPoint4D(x, y, z, w);
    949  }
    950 
    951  template <class F>
    952  Point4DTyped<TargetUnits, F> TransformPoint(
    953      const Point4DTyped<SourceUnits, F>& aPoint) const {
    954    Point4DTyped<TargetUnits, F> retPoint;
    955 
    956    retPoint.x =
    957        aPoint.x * _11 + aPoint.y * _21 + aPoint.z * _31 + aPoint.w * _41;
    958    retPoint.y =
    959        aPoint.x * _12 + aPoint.y * _22 + aPoint.z * _32 + aPoint.w * _42;
    960    retPoint.z =
    961        aPoint.x * _13 + aPoint.y * _23 + aPoint.z * _33 + aPoint.w * _43;
    962    retPoint.w =
    963        aPoint.x * _14 + aPoint.y * _24 + aPoint.z * _34 + aPoint.w * _44;
    964 
    965    return retPoint;
    966  }
    967 
    968  template <class F>
    969  Point3DTyped<TargetUnits, F> TransformPoint(
    970      const Point3DTyped<SourceUnits, F>& aPoint) const {
    971    Point3DTyped<TargetUnits, F> result;
    972    result.x = aPoint.x * _11 + aPoint.y * _21 + aPoint.z * _31 + _41;
    973    result.y = aPoint.x * _12 + aPoint.y * _22 + aPoint.z * _32 + _42;
    974    result.z = aPoint.x * _13 + aPoint.y * _23 + aPoint.z * _33 + _43;
    975 
    976    result /= (aPoint.x * _14 + aPoint.y * _24 + aPoint.z * _34 + _44);
    977 
    978    return result;
    979  }
    980 
    981  template <class F>
    982  PointTyped<TargetUnits, F> TransformPoint(
    983      const PointTyped<SourceUnits, F>& aPoint) const {
    984    Point4DTyped<SourceUnits, F> temp(aPoint.x, aPoint.y, 0, 1);
    985    return TransformPoint(temp).As2DPoint();
    986  }
    987 
    988  template <class F>
    989  GFX2D_API RectTyped<TargetUnits, F> TransformBounds(
    990      const RectTyped<SourceUnits, F>& aRect) const {
    991    // If you change this also change Matrix4x4TypedFlagged::TransformBounds to
    992    // match.
    993    PointTyped<TargetUnits, F> quad[4];
    994    F min_x, max_x;
    995    F min_y, max_y;
    996 
    997    quad[0] = TransformPoint(aRect.TopLeft());
    998    quad[1] = TransformPoint(aRect.TopRight());
    999    quad[2] = TransformPoint(aRect.BottomLeft());
   1000    quad[3] = TransformPoint(aRect.BottomRight());
   1001 
   1002    min_x = max_x = quad[0].x;
   1003    min_y = max_y = quad[0].y;
   1004 
   1005    for (int i = 1; i < 4; i++) {
   1006      if (quad[i].x < min_x) {
   1007        min_x = quad[i].x;
   1008      }
   1009      if (quad[i].x > max_x) {
   1010        max_x = quad[i].x;
   1011      }
   1012 
   1013      if (quad[i].y < min_y) {
   1014        min_y = quad[i].y;
   1015      }
   1016      if (quad[i].y > max_y) {
   1017        max_y = quad[i].y;
   1018      }
   1019    }
   1020 
   1021    return RectTyped<TargetUnits, F>(min_x, min_y, max_x - min_x,
   1022                                     max_y - min_y);
   1023  }
   1024 
   1025  static Matrix4x4Typed Translation(T aX, T aY, T aZ) {
   1026    return Matrix4x4Typed(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
   1027                          0.0f, 1.0f, 0.0f, aX, aY, aZ, 1.0f);
   1028  }
   1029 
   1030  static Matrix4x4Typed Translation(const TargetPoint3D& aP) {
   1031    return Translation(aP.x, aP.y, aP.z);
   1032  }
   1033 
   1034  static Matrix4x4Typed Translation(const TargetPoint& aP) {
   1035    return Translation(aP.x, aP.y, 0);
   1036  }
   1037 
   1038  /**
   1039   * Apply a translation to this matrix.
   1040   *
   1041   * The "Pre" in this method's name means that the translation is applied
   1042   * -before- this matrix's existing transformation. That is, any vector that
   1043   * is multiplied by the resulting matrix will first be translated, then be
   1044   * transformed by the original transform.
   1045   *
   1046   * Calling this method will result in this matrix having the same value as
   1047   * the result of:
   1048   *
   1049   *   Matrix4x4::Translation(x, y) * this
   1050   *
   1051   * (Note that in performance critical code multiplying by the result of a
   1052   * Translation()/Scaling() call is not recommended since that results in a
   1053   * full matrix multiply involving 64 floating-point multiplications. Calling
   1054   * this method would be preferred since it only involves 12 floating-point
   1055   * multiplications.)
   1056   */
   1057  Matrix4x4Typed& PreTranslate(T aX, T aY, T aZ) {
   1058    _41 += aX * _11 + aY * _21 + aZ * _31;
   1059    _42 += aX * _12 + aY * _22 + aZ * _32;
   1060    _43 += aX * _13 + aY * _23 + aZ * _33;
   1061    _44 += aX * _14 + aY * _24 + aZ * _34;
   1062 
   1063    return *this;
   1064  }
   1065 
   1066  Matrix4x4Typed& PreTranslate(const Point3DTyped<UnknownUnits, T>& aPoint) {
   1067    return PreTranslate(aPoint.x, aPoint.y, aPoint.z);
   1068  }
   1069 
   1070  /**
   1071   * Similar to PreTranslate, but the translation is applied -after- this
   1072   * matrix's existing transformation instead of before it.
   1073   *
   1074   * This method is generally less used than PreTranslate since typically code
   1075   * wants to adjust an existing user space to device space matrix to create a
   1076   * transform to device space from a -new- user space (translated from the
   1077   * previous user space). In that case consumers will need to use the Pre*
   1078   * variants of the matrix methods rather than using the Post* methods, since
   1079   * the Post* methods add a transform to the device space end of the
   1080   * transformation.
   1081   */
   1082  Matrix4x4Typed& PostTranslate(T aX, T aY, T aZ) {
   1083    _11 += _14 * aX;
   1084    _21 += _24 * aX;
   1085    _31 += _34 * aX;
   1086    _41 += _44 * aX;
   1087    _12 += _14 * aY;
   1088    _22 += _24 * aY;
   1089    _32 += _34 * aY;
   1090    _42 += _44 * aY;
   1091    _13 += _14 * aZ;
   1092    _23 += _24 * aZ;
   1093    _33 += _34 * aZ;
   1094    _43 += _44 * aZ;
   1095 
   1096    return *this;
   1097  }
   1098 
   1099  Matrix4x4Typed& PostTranslate(const TargetPoint3D& aPoint) {
   1100    return PostTranslate(aPoint.x, aPoint.y, aPoint.z);
   1101  }
   1102 
   1103  Matrix4x4Typed& PostTranslate(const TargetPoint& aPoint) {
   1104    return PostTranslate(aPoint.x, aPoint.y, 0);
   1105  }
   1106 
   1107  static Matrix4x4Typed Scaling(T aScaleX, T aScaleY, T aScaleZ) {
   1108    return Matrix4x4Typed(aScaleX, 0.0f, 0.0f, 0.0f, 0.0f, aScaleY, 0.0f, 0.0f,
   1109                          0.0f, 0.0f, aScaleZ, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
   1110  }
   1111 
   1112  /**
   1113   * Similar to PreTranslate, but applies a scale instead of a translation.
   1114   */
   1115  Matrix4x4Typed& PreScale(T aX, T aY, T aZ) {
   1116    _11 *= aX;
   1117    _12 *= aX;
   1118    _13 *= aX;
   1119    _14 *= aX;
   1120    _21 *= aY;
   1121    _22 *= aY;
   1122    _23 *= aY;
   1123    _24 *= aY;
   1124    _31 *= aZ;
   1125    _32 *= aZ;
   1126    _33 *= aZ;
   1127    _34 *= aZ;
   1128 
   1129    return *this;
   1130  }
   1131 
   1132  template <typename NewSourceUnits>
   1133  [[nodiscard]] Matrix4x4Typed<NewSourceUnits, TargetUnits> PreScale(
   1134      const ScaleFactor<NewSourceUnits, SourceUnits>& aScale) const {
   1135    auto clone = Cast<Matrix4x4Typed<NewSourceUnits, TargetUnits>>();
   1136    clone.PreScale(aScale.scale, aScale.scale, 1);
   1137    return clone;
   1138  }
   1139 
   1140  template <typename NewSourceUnits>
   1141  [[nodiscard]] Matrix4x4Typed<NewSourceUnits, TargetUnits> PreScale(
   1142      const BaseScaleFactors2D<NewSourceUnits, SourceUnits, T>& aScale) const {
   1143    auto clone = Cast<Matrix4x4Typed<NewSourceUnits, TargetUnits>>();
   1144    clone.PreScale(aScale.xScale, aScale.yScale, 1);
   1145    return clone;
   1146  }
   1147 
   1148  /**
   1149   * Similar to PostTranslate, but applies a scale instead of a translation.
   1150   */
   1151  Matrix4x4Typed& PostScale(T aScaleX, T aScaleY, T aScaleZ) {
   1152    _11 *= aScaleX;
   1153    _21 *= aScaleX;
   1154    _31 *= aScaleX;
   1155    _41 *= aScaleX;
   1156    _12 *= aScaleY;
   1157    _22 *= aScaleY;
   1158    _32 *= aScaleY;
   1159    _42 *= aScaleY;
   1160    _13 *= aScaleZ;
   1161    _23 *= aScaleZ;
   1162    _33 *= aScaleZ;
   1163    _43 *= aScaleZ;
   1164 
   1165    return *this;
   1166  }
   1167 
   1168  template <typename NewTargetUnits>
   1169  [[nodiscard]] Matrix4x4Typed<SourceUnits, NewTargetUnits> PostScale(
   1170      const ScaleFactor<TargetUnits, NewTargetUnits>& aScale) const {
   1171    auto clone = Cast<Matrix4x4Typed<SourceUnits, NewTargetUnits>>();
   1172    clone.PostScale(aScale.scale, aScale.scale, 1);
   1173    return clone;
   1174  }
   1175 
   1176  template <typename NewTargetUnits>
   1177  [[nodiscard]] Matrix4x4Typed<SourceUnits, NewTargetUnits> PostScale(
   1178      const BaseScaleFactors2D<TargetUnits, NewTargetUnits, T>& aScale) const {
   1179    auto clone = Cast<Matrix4x4Typed<SourceUnits, NewTargetUnits>>();
   1180    clone.PostScale(aScale.xScale, aScale.yScale, 1);
   1181    return clone;
   1182  }
   1183 
   1184  void SkewXY(T aSkew) { (*this)[1] += (*this)[0] * aSkew; }
   1185 
   1186  void SkewXZ(T aSkew) { (*this)[2] += (*this)[0] * aSkew; }
   1187 
   1188  void SkewYZ(T aSkew) { (*this)[2] += (*this)[1] * aSkew; }
   1189 
   1190  Matrix4x4Typed& ChangeBasis(const Point3DTyped<UnknownUnits, T>& aOrigin) {
   1191    return ChangeBasis(aOrigin.x, aOrigin.y, aOrigin.z);
   1192  }
   1193 
   1194  Matrix4x4Typed& ChangeBasis(T aX, T aY, T aZ) {
   1195    // Translate to the origin before applying this matrix
   1196    PreTranslate(-aX, -aY, -aZ);
   1197 
   1198    // Translate back into position after applying this matrix
   1199    PostTranslate(aX, aY, aZ);
   1200 
   1201    return *this;
   1202  }
   1203 
   1204  Matrix4x4Typed& Transpose() {
   1205    std::swap(_12, _21);
   1206    std::swap(_13, _31);
   1207    std::swap(_14, _41);
   1208 
   1209    std::swap(_23, _32);
   1210    std::swap(_24, _42);
   1211 
   1212    std::swap(_34, _43);
   1213 
   1214    return *this;
   1215  }
   1216 
   1217  bool operator==(const Matrix4x4Typed& o) const {
   1218    // XXX would be nice to memcmp here, but that breaks IEEE 754 semantics
   1219    return _11 == o._11 && _12 == o._12 && _13 == o._13 && _14 == o._14 &&
   1220           _21 == o._21 && _22 == o._22 && _23 == o._23 && _24 == o._24 &&
   1221           _31 == o._31 && _32 == o._32 && _33 == o._33 && _34 == o._34 &&
   1222           _41 == o._41 && _42 == o._42 && _43 == o._43 && _44 == o._44;
   1223  }
   1224 
   1225  bool operator!=(const Matrix4x4Typed& o) const { return !((*this) == o); }
   1226 
   1227  Matrix4x4Typed& operator=(const Matrix4x4Typed& aOther) = default;
   1228 
   1229  template <typename NewTargetUnits>
   1230  Matrix4x4Typed<SourceUnits, NewTargetUnits, T> operator*(
   1231      const Matrix4x4Typed<TargetUnits, NewTargetUnits, T>& aMatrix) const {
   1232    Matrix4x4Typed<SourceUnits, NewTargetUnits, T> matrix;
   1233 
   1234    matrix._11 = _11 * aMatrix._11 + _12 * aMatrix._21 + _13 * aMatrix._31 +
   1235                 _14 * aMatrix._41;
   1236    matrix._21 = _21 * aMatrix._11 + _22 * aMatrix._21 + _23 * aMatrix._31 +
   1237                 _24 * aMatrix._41;
   1238    matrix._31 = _31 * aMatrix._11 + _32 * aMatrix._21 + _33 * aMatrix._31 +
   1239                 _34 * aMatrix._41;
   1240    matrix._41 = _41 * aMatrix._11 + _42 * aMatrix._21 + _43 * aMatrix._31 +
   1241                 _44 * aMatrix._41;
   1242    matrix._12 = _11 * aMatrix._12 + _12 * aMatrix._22 + _13 * aMatrix._32 +
   1243                 _14 * aMatrix._42;
   1244    matrix._22 = _21 * aMatrix._12 + _22 * aMatrix._22 + _23 * aMatrix._32 +
   1245                 _24 * aMatrix._42;
   1246    matrix._32 = _31 * aMatrix._12 + _32 * aMatrix._22 + _33 * aMatrix._32 +
   1247                 _34 * aMatrix._42;
   1248    matrix._42 = _41 * aMatrix._12 + _42 * aMatrix._22 + _43 * aMatrix._32 +
   1249                 _44 * aMatrix._42;
   1250    matrix._13 = _11 * aMatrix._13 + _12 * aMatrix._23 + _13 * aMatrix._33 +
   1251                 _14 * aMatrix._43;
   1252    matrix._23 = _21 * aMatrix._13 + _22 * aMatrix._23 + _23 * aMatrix._33 +
   1253                 _24 * aMatrix._43;
   1254    matrix._33 = _31 * aMatrix._13 + _32 * aMatrix._23 + _33 * aMatrix._33 +
   1255                 _34 * aMatrix._43;
   1256    matrix._43 = _41 * aMatrix._13 + _42 * aMatrix._23 + _43 * aMatrix._33 +
   1257                 _44 * aMatrix._43;
   1258    matrix._14 = _11 * aMatrix._14 + _12 * aMatrix._24 + _13 * aMatrix._34 +
   1259                 _14 * aMatrix._44;
   1260    matrix._24 = _21 * aMatrix._14 + _22 * aMatrix._24 + _23 * aMatrix._34 +
   1261                 _24 * aMatrix._44;
   1262    matrix._34 = _31 * aMatrix._14 + _32 * aMatrix._24 + _33 * aMatrix._34 +
   1263                 _34 * aMatrix._44;
   1264    matrix._44 = _41 * aMatrix._14 + _42 * aMatrix._24 + _43 * aMatrix._34 +
   1265                 _44 * aMatrix._44;
   1266 
   1267    return matrix;
   1268  }
   1269 
   1270  Matrix4x4Typed& operator*=(
   1271      const Matrix4x4Typed<TargetUnits, TargetUnits, T>& aMatrix) {
   1272    *this = *this * aMatrix;
   1273    return *this;
   1274  }
   1275 
   1276  /* Returns true if the matrix is an identity matrix.
   1277   */
   1278  bool IsIdentity() const {
   1279    return _11 == 1.0f && _12 == 0.0f && _13 == 0.0f && _14 == 0.0f &&
   1280           _21 == 0.0f && _22 == 1.0f && _23 == 0.0f && _24 == 0.0f &&
   1281           _31 == 0.0f && _32 == 0.0f && _33 == 1.0f && _34 == 0.0f &&
   1282           _41 == 0.0f && _42 == 0.0f && _43 == 0.0f && _44 == 1.0f;
   1283  }
   1284 
   1285  bool IsSingular() const { return Determinant() == 0.0; }
   1286 
   1287  T Determinant() const {
   1288    return _14 * _23 * _32 * _41 - _13 * _24 * _32 * _41 -
   1289           _14 * _22 * _33 * _41 + _12 * _24 * _33 * _41 +
   1290           _13 * _22 * _34 * _41 - _12 * _23 * _34 * _41 -
   1291           _14 * _23 * _31 * _42 + _13 * _24 * _31 * _42 +
   1292           _14 * _21 * _33 * _42 - _11 * _24 * _33 * _42 -
   1293           _13 * _21 * _34 * _42 + _11 * _23 * _34 * _42 +
   1294           _14 * _22 * _31 * _43 - _12 * _24 * _31 * _43 -
   1295           _14 * _21 * _32 * _43 + _11 * _24 * _32 * _43 +
   1296           _12 * _21 * _34 * _43 - _11 * _22 * _34 * _43 -
   1297           _13 * _22 * _31 * _44 + _12 * _23 * _31 * _44 +
   1298           _13 * _21 * _32 * _44 - _11 * _23 * _32 * _44 -
   1299           _12 * _21 * _33 * _44 + _11 * _22 * _33 * _44;
   1300  }
   1301 
   1302  // Invert() is not unit-correct. Prefer Inverse() where possible.
   1303  bool Invert() {
   1304    T det = Determinant();
   1305    if (!det) {
   1306      return false;
   1307    }
   1308 
   1309    Matrix4x4Typed<SourceUnits, TargetUnits, T> result;
   1310    result._11 = _23 * _34 * _42 - _24 * _33 * _42 + _24 * _32 * _43 -
   1311                 _22 * _34 * _43 - _23 * _32 * _44 + _22 * _33 * _44;
   1312    result._12 = _14 * _33 * _42 - _13 * _34 * _42 - _14 * _32 * _43 +
   1313                 _12 * _34 * _43 + _13 * _32 * _44 - _12 * _33 * _44;
   1314    result._13 = _13 * _24 * _42 - _14 * _23 * _42 + _14 * _22 * _43 -
   1315                 _12 * _24 * _43 - _13 * _22 * _44 + _12 * _23 * _44;
   1316    result._14 = _14 * _23 * _32 - _13 * _24 * _32 - _14 * _22 * _33 +
   1317                 _12 * _24 * _33 + _13 * _22 * _34 - _12 * _23 * _34;
   1318    result._21 = _24 * _33 * _41 - _23 * _34 * _41 - _24 * _31 * _43 +
   1319                 _21 * _34 * _43 + _23 * _31 * _44 - _21 * _33 * _44;
   1320    result._22 = _13 * _34 * _41 - _14 * _33 * _41 + _14 * _31 * _43 -
   1321                 _11 * _34 * _43 - _13 * _31 * _44 + _11 * _33 * _44;
   1322    result._23 = _14 * _23 * _41 - _13 * _24 * _41 - _14 * _21 * _43 +
   1323                 _11 * _24 * _43 + _13 * _21 * _44 - _11 * _23 * _44;
   1324    result._24 = _13 * _24 * _31 - _14 * _23 * _31 + _14 * _21 * _33 -
   1325                 _11 * _24 * _33 - _13 * _21 * _34 + _11 * _23 * _34;
   1326    result._31 = _22 * _34 * _41 - _24 * _32 * _41 + _24 * _31 * _42 -
   1327                 _21 * _34 * _42 - _22 * _31 * _44 + _21 * _32 * _44;
   1328    result._32 = _14 * _32 * _41 - _12 * _34 * _41 - _14 * _31 * _42 +
   1329                 _11 * _34 * _42 + _12 * _31 * _44 - _11 * _32 * _44;
   1330    result._33 = _12 * _24 * _41 - _14 * _22 * _41 + _14 * _21 * _42 -
   1331                 _11 * _24 * _42 - _12 * _21 * _44 + _11 * _22 * _44;
   1332    result._34 = _14 * _22 * _31 - _12 * _24 * _31 - _14 * _21 * _32 +
   1333                 _11 * _24 * _32 + _12 * _21 * _34 - _11 * _22 * _34;
   1334    result._41 = _23 * _32 * _41 - _22 * _33 * _41 - _23 * _31 * _42 +
   1335                 _21 * _33 * _42 + _22 * _31 * _43 - _21 * _32 * _43;
   1336    result._42 = _12 * _33 * _41 - _13 * _32 * _41 + _13 * _31 * _42 -
   1337                 _11 * _33 * _42 - _12 * _31 * _43 + _11 * _32 * _43;
   1338    result._43 = _13 * _22 * _41 - _12 * _23 * _41 - _13 * _21 * _42 +
   1339                 _11 * _23 * _42 + _12 * _21 * _43 - _11 * _22 * _43;
   1340    result._44 = _12 * _23 * _31 - _13 * _22 * _31 + _13 * _21 * _32 -
   1341                 _11 * _23 * _32 - _12 * _21 * _33 + _11 * _22 * _33;
   1342 
   1343    result._11 /= det;
   1344    result._12 /= det;
   1345    result._13 /= det;
   1346    result._14 /= det;
   1347    result._21 /= det;
   1348    result._22 /= det;
   1349    result._23 /= det;
   1350    result._24 /= det;
   1351    result._31 /= det;
   1352    result._32 /= det;
   1353    result._33 /= det;
   1354    result._34 /= det;
   1355    result._41 /= det;
   1356    result._42 /= det;
   1357    result._43 /= det;
   1358    result._44 /= det;
   1359    *this = result;
   1360 
   1361    return true;
   1362  }
   1363 
   1364  Matrix4x4Typed<TargetUnits, SourceUnits, T> Inverse() const {
   1365    typedef Matrix4x4Typed<TargetUnits, SourceUnits, T> InvertedMatrix;
   1366    InvertedMatrix clone = Cast<InvertedMatrix>();
   1367    DebugOnly<bool> inverted = clone.Invert();
   1368    MOZ_ASSERT(inverted,
   1369               "Attempted to get the inverse of a non-invertible matrix");
   1370    return clone;
   1371  }
   1372 
   1373  Maybe<Matrix4x4Typed<TargetUnits, SourceUnits, T>> MaybeInverse() const {
   1374    typedef Matrix4x4Typed<TargetUnits, SourceUnits, T> InvertedMatrix;
   1375    InvertedMatrix clone = Cast<InvertedMatrix>();
   1376    if (clone.Invert()) {
   1377      return Some(clone);
   1378    }
   1379    return Nothing();
   1380  }
   1381 
   1382  void Normalize() {
   1383    for (int i = 0; i < 4; i++) {
   1384      for (int j = 0; j < 4; j++) {
   1385        (*this)[i][j] /= (*this)[3][3];
   1386      }
   1387    }
   1388  }
   1389 
   1390  bool FuzzyEqual(const Matrix4x4Typed& o) const {
   1391    return gfx::FuzzyEqual(_11, o._11) && gfx::FuzzyEqual(_12, o._12) &&
   1392           gfx::FuzzyEqual(_13, o._13) && gfx::FuzzyEqual(_14, o._14) &&
   1393           gfx::FuzzyEqual(_21, o._21) && gfx::FuzzyEqual(_22, o._22) &&
   1394           gfx::FuzzyEqual(_23, o._23) && gfx::FuzzyEqual(_24, o._24) &&
   1395           gfx::FuzzyEqual(_31, o._31) && gfx::FuzzyEqual(_32, o._32) &&
   1396           gfx::FuzzyEqual(_33, o._33) && gfx::FuzzyEqual(_34, o._34) &&
   1397           gfx::FuzzyEqual(_41, o._41) && gfx::FuzzyEqual(_42, o._42) &&
   1398           gfx::FuzzyEqual(_43, o._43) && gfx::FuzzyEqual(_44, o._44);
   1399  }
   1400 
   1401  bool FuzzyEqualsMultiplicative(const Matrix4x4Typed& o) const {
   1402    return ::mozilla::FuzzyEqualsMultiplicative(_11, o._11) &&
   1403           ::mozilla::FuzzyEqualsMultiplicative(_12, o._12) &&
   1404           ::mozilla::FuzzyEqualsMultiplicative(_13, o._13) &&
   1405           ::mozilla::FuzzyEqualsMultiplicative(_14, o._14) &&
   1406           ::mozilla::FuzzyEqualsMultiplicative(_21, o._21) &&
   1407           ::mozilla::FuzzyEqualsMultiplicative(_22, o._22) &&
   1408           ::mozilla::FuzzyEqualsMultiplicative(_23, o._23) &&
   1409           ::mozilla::FuzzyEqualsMultiplicative(_24, o._24) &&
   1410           ::mozilla::FuzzyEqualsMultiplicative(_31, o._31) &&
   1411           ::mozilla::FuzzyEqualsMultiplicative(_32, o._32) &&
   1412           ::mozilla::FuzzyEqualsMultiplicative(_33, o._33) &&
   1413           ::mozilla::FuzzyEqualsMultiplicative(_34, o._34) &&
   1414           ::mozilla::FuzzyEqualsMultiplicative(_41, o._41) &&
   1415           ::mozilla::FuzzyEqualsMultiplicative(_42, o._42) &&
   1416           ::mozilla::FuzzyEqualsMultiplicative(_43, o._43) &&
   1417           ::mozilla::FuzzyEqualsMultiplicative(_44, o._44);
   1418  }
   1419 
   1420  bool IsBackfaceVisible() const {
   1421    // Inverse()._33 < 0;
   1422    T det = Determinant();
   1423    T __33 = _12 * _24 * _41 - _14 * _22 * _41 + _14 * _21 * _42 -
   1424             _11 * _24 * _42 - _12 * _21 * _44 + _11 * _22 * _44;
   1425    return (__33 * det) < 0;
   1426  }
   1427 
   1428  Matrix4x4Typed& NudgeToIntegersFixedEpsilon() {
   1429    NudgeToInteger(&_11);
   1430    NudgeToInteger(&_12);
   1431    NudgeToInteger(&_13);
   1432    NudgeToInteger(&_14);
   1433    NudgeToInteger(&_21);
   1434    NudgeToInteger(&_22);
   1435    NudgeToInteger(&_23);
   1436    NudgeToInteger(&_24);
   1437    NudgeToInteger(&_31);
   1438    NudgeToInteger(&_32);
   1439    NudgeToInteger(&_33);
   1440    NudgeToInteger(&_34);
   1441    static const float error = 1e-5f;
   1442    NudgeToInteger(&_41, error);
   1443    NudgeToInteger(&_42, error);
   1444    NudgeToInteger(&_43, error);
   1445    NudgeToInteger(&_44, error);
   1446    return *this;
   1447  }
   1448 
   1449  Point4D TransposedVector(int aIndex) const {
   1450    MOZ_ASSERT(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index");
   1451    return Point4DTyped<UnknownUnits, T>(*((&_11) + aIndex), *((&_21) + aIndex),
   1452                                         *((&_31) + aIndex),
   1453                                         *((&_41) + aIndex));
   1454  }
   1455 
   1456  void SetTransposedVector(int aIndex, Point4DTyped<UnknownUnits, T>& aVector) {
   1457    MOZ_ASSERT(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index");
   1458    *((&_11) + aIndex) = aVector.x;
   1459    *((&_21) + aIndex) = aVector.y;
   1460    *((&_31) + aIndex) = aVector.z;
   1461    *((&_41) + aIndex) = aVector.w;
   1462  }
   1463 
   1464  bool Decompose(Point3DTyped<UnknownUnits, T>& translation,
   1465                 BaseQuaternion<T>& rotation,
   1466                 Point3DTyped<UnknownUnits, T>& scale) const {
   1467    // Ensure matrix can be normalized
   1468    if (gfx::FuzzyEqual(_44, 0.0f)) {
   1469      return false;
   1470    }
   1471    Matrix4x4Typed mat = *this;
   1472    mat.Normalize();
   1473    if (HasPerspectiveComponent()) {
   1474      // We do not support projection matrices
   1475      return false;
   1476    }
   1477 
   1478    // Extract translation
   1479    translation.x = mat._41;
   1480    translation.y = mat._42;
   1481    translation.z = mat._43;
   1482 
   1483    // Remove translation
   1484    mat._41 = 0.0f;
   1485    mat._42 = 0.0f;
   1486    mat._43 = 0.0f;
   1487 
   1488    // Extract scale
   1489    scale.x = sqrtf(_11 * _11 + _21 * _21 + _31 * _31);
   1490    scale.y = sqrtf(_12 * _12 + _22 * _22 + _32 * _32);
   1491    scale.z = sqrtf(_13 * _13 + _23 * _23 + _33 * _33);
   1492 
   1493    // Remove scale
   1494    if (gfx::FuzzyEqual(scale.x, 0.0f) || gfx::FuzzyEqual(scale.y, 0.0f) ||
   1495        gfx::FuzzyEqual(scale.z, 0.0f)) {
   1496      // We do not support matrices with a zero scale component
   1497      return false;
   1498    }
   1499 
   1500    // Extract rotation
   1501    rotation.SetFromRotationMatrix(this->ToUnknownMatrix());
   1502    return true;
   1503  }
   1504 
   1505  // Sets this matrix to a rotation matrix given by aQuat.
   1506  // This quaternion *MUST* be normalized!
   1507  // Implemented in Quaternion.cpp
   1508  void SetRotationFromQuaternion(const BaseQuaternion<T>& q) {
   1509    const T x2 = q.x + q.x, y2 = q.y + q.y, z2 = q.z + q.z;
   1510    const T xx = q.x * x2, xy = q.x * y2, xz = q.x * z2;
   1511    const T yy = q.y * y2, yz = q.y * z2, zz = q.z * z2;
   1512    const T wx = q.w * x2, wy = q.w * y2, wz = q.w * z2;
   1513 
   1514    _11 = 1.0f - (yy + zz);
   1515    _21 = xy - wz;
   1516    _31 = xz + wy;
   1517    _41 = 0.0f;
   1518 
   1519    _12 = xy + wz;
   1520    _22 = 1.0f - (xx + zz);
   1521    _32 = yz - wx;
   1522    _42 = 0.0f;
   1523 
   1524    _13 = xz - wy;
   1525    _23 = yz + wx;
   1526    _33 = 1.0f - (xx + yy);
   1527    _43 = 0.0f;
   1528 
   1529    _14 = _42 = _43 = 0.0f;
   1530    _44 = 1.0f;
   1531  }
   1532 
   1533  // Set all the members of the matrix to NaN
   1534  void SetNAN() {
   1535    _11 = UnspecifiedNaN<T>();
   1536    _21 = UnspecifiedNaN<T>();
   1537    _31 = UnspecifiedNaN<T>();
   1538    _41 = UnspecifiedNaN<T>();
   1539    _12 = UnspecifiedNaN<T>();
   1540    _22 = UnspecifiedNaN<T>();
   1541    _32 = UnspecifiedNaN<T>();
   1542    _42 = UnspecifiedNaN<T>();
   1543    _13 = UnspecifiedNaN<T>();
   1544    _23 = UnspecifiedNaN<T>();
   1545    _33 = UnspecifiedNaN<T>();
   1546    _43 = UnspecifiedNaN<T>();
   1547    _14 = UnspecifiedNaN<T>();
   1548    _24 = UnspecifiedNaN<T>();
   1549    _34 = UnspecifiedNaN<T>();
   1550    _44 = UnspecifiedNaN<T>();
   1551  }
   1552 
   1553  // Verifies that the matrix contains no Infs or NaNs
   1554  bool IsFinite() const {
   1555    return std::isfinite(_11) && std::isfinite(_12) && std::isfinite(_13) &&
   1556           std::isfinite(_14) && std::isfinite(_21) && std::isfinite(_22) &&
   1557           std::isfinite(_23) && std::isfinite(_24) && std::isfinite(_31) &&
   1558           std::isfinite(_32) && std::isfinite(_33) && std::isfinite(_34) &&
   1559           std::isfinite(_41) && std::isfinite(_42) && std::isfinite(_43) &&
   1560           std::isfinite(_44);
   1561  }
   1562 
   1563  void SkewXY(double aXSkew, double aYSkew) {
   1564    // XXX Is double precision really necessary here
   1565    T tanX = SafeTangent(aXSkew);
   1566    T tanY = SafeTangent(aYSkew);
   1567    T temp;
   1568 
   1569    temp = _11;
   1570    _11 += tanY * _21;
   1571    _21 += tanX * temp;
   1572 
   1573    temp = _12;
   1574    _12 += tanY * _22;
   1575    _22 += tanX * temp;
   1576 
   1577    temp = _13;
   1578    _13 += tanY * _23;
   1579    _23 += tanX * temp;
   1580 
   1581    temp = _14;
   1582    _14 += tanY * _24;
   1583    _24 += tanX * temp;
   1584  }
   1585 
   1586  void RotateX(double aTheta) {
   1587    // XXX Is double precision really necessary here
   1588    double cosTheta = FlushToZero(cos(aTheta));
   1589    double sinTheta = FlushToZero(sin(aTheta));
   1590 
   1591    T temp;
   1592 
   1593    temp = _21;
   1594    _21 = cosTheta * _21 + sinTheta * _31;
   1595    _31 = -sinTheta * temp + cosTheta * _31;
   1596 
   1597    temp = _22;
   1598    _22 = cosTheta * _22 + sinTheta * _32;
   1599    _32 = -sinTheta * temp + cosTheta * _32;
   1600 
   1601    temp = _23;
   1602    _23 = cosTheta * _23 + sinTheta * _33;
   1603    _33 = -sinTheta * temp + cosTheta * _33;
   1604 
   1605    temp = _24;
   1606    _24 = cosTheta * _24 + sinTheta * _34;
   1607    _34 = -sinTheta * temp + cosTheta * _34;
   1608  }
   1609 
   1610  void RotateY(double aTheta) {
   1611    // XXX Is double precision really necessary here
   1612    double cosTheta = FlushToZero(cos(aTheta));
   1613    double sinTheta = FlushToZero(sin(aTheta));
   1614 
   1615    T temp;
   1616 
   1617    temp = _11;
   1618    _11 = cosTheta * _11 + -sinTheta * _31;
   1619    _31 = sinTheta * temp + cosTheta * _31;
   1620 
   1621    temp = _12;
   1622    _12 = cosTheta * _12 + -sinTheta * _32;
   1623    _32 = sinTheta * temp + cosTheta * _32;
   1624 
   1625    temp = _13;
   1626    _13 = cosTheta * _13 + -sinTheta * _33;
   1627    _33 = sinTheta * temp + cosTheta * _33;
   1628 
   1629    temp = _14;
   1630    _14 = cosTheta * _14 + -sinTheta * _34;
   1631    _34 = sinTheta * temp + cosTheta * _34;
   1632  }
   1633 
   1634  void RotateZ(double aTheta) {
   1635    // XXX Is double precision really necessary here
   1636    double cosTheta = FlushToZero(cos(aTheta));
   1637    double sinTheta = FlushToZero(sin(aTheta));
   1638 
   1639    T temp;
   1640 
   1641    temp = _11;
   1642    _11 = cosTheta * _11 + sinTheta * _21;
   1643    _21 = -sinTheta * temp + cosTheta * _21;
   1644 
   1645    temp = _12;
   1646    _12 = cosTheta * _12 + sinTheta * _22;
   1647    _22 = -sinTheta * temp + cosTheta * _22;
   1648 
   1649    temp = _13;
   1650    _13 = cosTheta * _13 + sinTheta * _23;
   1651    _23 = -sinTheta * temp + cosTheta * _23;
   1652 
   1653    temp = _14;
   1654    _14 = cosTheta * _14 + sinTheta * _24;
   1655    _24 = -sinTheta * temp + cosTheta * _24;
   1656  }
   1657 
   1658  // Sets this matrix to a rotation matrix about a
   1659  // vector [x,y,z] by angle theta. The vector is normalized
   1660  // to a unit vector.
   1661  // https://drafts.csswg.org/css-transforms-2/#Rotate3dDefined
   1662  void SetRotateAxisAngle(double aX, double aY, double aZ, double aTheta) {
   1663    Point3DTyped<UnknownUnits, T> vector(aX, aY, aZ);
   1664    if (!vector.Length()) {
   1665      return;
   1666    }
   1667    vector.RobustNormalize();
   1668 
   1669    double x = vector.x;
   1670    double y = vector.y;
   1671    double z = vector.z;
   1672 
   1673    double cosTheta = FlushToZero(cos(aTheta));
   1674    double sinTheta = FlushToZero(sin(aTheta));
   1675 
   1676    // sin(aTheta / 2) * cos(aTheta / 2)
   1677    double sc = sinTheta / 2;
   1678    // pow(sin(aTheta / 2), 2)
   1679    double sq = (1 - cosTheta) / 2;
   1680 
   1681    _11 = 1 - 2 * (y * y + z * z) * sq;
   1682    _12 = 2 * (x * y * sq + z * sc);
   1683    _13 = 2 * (x * z * sq - y * sc);
   1684    _14 = 0.0f;
   1685    _21 = 2 * (x * y * sq - z * sc);
   1686    _22 = 1 - 2 * (x * x + z * z) * sq;
   1687    _23 = 2 * (y * z * sq + x * sc);
   1688    _24 = 0.0f;
   1689    _31 = 2 * (x * z * sq + y * sc);
   1690    _32 = 2 * (y * z * sq - x * sc);
   1691    _33 = 1 - 2 * (x * x + y * y) * sq;
   1692    _34 = 0.0f;
   1693    _41 = 0.0f;
   1694    _42 = 0.0f;
   1695    _43 = 0.0f;
   1696    _44 = 1.0f;
   1697  }
   1698 
   1699  void Perspective(T aDepth) {
   1700    MOZ_ASSERT(aDepth > 0.0f, "Perspective must be positive!");
   1701    _31 += -1.0 / aDepth * _41;
   1702    _32 += -1.0 / aDepth * _42;
   1703    _33 += -1.0 / aDepth * _43;
   1704    _34 += -1.0 / aDepth * _44;
   1705  }
   1706 
   1707  Point3D GetNormalVector() const {
   1708    // Define a plane in transformed space as the transformations
   1709    // of 3 points on the z=0 screen plane.
   1710    Point3DTyped<UnknownUnits, T> a =
   1711        TransformPoint(Point3DTyped<UnknownUnits, T>(0, 0, 0));
   1712    Point3DTyped<UnknownUnits, T> b =
   1713        TransformPoint(Point3DTyped<UnknownUnits, T>(0, 1, 0));
   1714    Point3DTyped<UnknownUnits, T> c =
   1715        TransformPoint(Point3DTyped<UnknownUnits, T>(1, 0, 0));
   1716 
   1717    // Convert to two vectors on the surface of the plane.
   1718    Point3DTyped<UnknownUnits, T> ab = b - a;
   1719    Point3DTyped<UnknownUnits, T> ac = c - a;
   1720 
   1721    return ac.CrossProduct(ab);
   1722  }
   1723 
   1724  /**
   1725   * Returns true if the matrix has any transform other
   1726   * than a straight translation.
   1727   */
   1728  bool HasNonTranslation() const {
   1729    return !gfx::FuzzyEqual(_11, 1.0) || !gfx::FuzzyEqual(_22, 1.0) ||
   1730           !gfx::FuzzyEqual(_12, 0.0) || !gfx::FuzzyEqual(_21, 0.0) ||
   1731           !gfx::FuzzyEqual(_13, 0.0) || !gfx::FuzzyEqual(_23, 0.0) ||
   1732           !gfx::FuzzyEqual(_31, 0.0) || !gfx::FuzzyEqual(_32, 0.0) ||
   1733           !gfx::FuzzyEqual(_33, 1.0);
   1734  }
   1735 
   1736  /**
   1737   * Returns true if the matrix is anything other than a straight
   1738   * translation by integers.
   1739   */
   1740  bool HasNonIntegerTranslation() const {
   1741    return HasNonTranslation() || !gfx::FuzzyEqual(_41, floor(_41 + 0.5)) ||
   1742           !gfx::FuzzyEqual(_42, floor(_42 + 0.5)) ||
   1743           !gfx::FuzzyEqual(_43, floor(_43 + 0.5));
   1744  }
   1745 
   1746  /**
   1747   * Return true if the matrix is with perspective (w).
   1748   */
   1749  bool HasPerspectiveComponent() const {
   1750    return _14 != 0 || _24 != 0 || _34 != 0 || _44 != 1;
   1751  }
   1752 
   1753  /* Returns true if the matrix is a rectilinear transformation (i.e.
   1754   * grid-aligned rectangles are transformed to grid-aligned rectangles).
   1755   * This should only be called on 2D matrices.
   1756   */
   1757  bool IsRectilinear() const {
   1758    MOZ_ASSERT(Is2D());
   1759    if (gfx::FuzzyEqual(_12, 0) && gfx::FuzzyEqual(_21, 0)) {
   1760      return true;
   1761    } else if (gfx::FuzzyEqual(_22, 0) && gfx::FuzzyEqual(_11, 0)) {
   1762      return true;
   1763    }
   1764    return false;
   1765  }
   1766 
   1767  /**
   1768   * Convert between typed and untyped matrices.
   1769   */
   1770  using UnknownMatrix = Matrix4x4Typed<UnknownUnits, UnknownUnits, T>;
   1771  UnknownMatrix ToUnknownMatrix() const {
   1772    return UnknownMatrix{_11, _12, _13, _14, _21, _22, _23, _24,
   1773                         _31, _32, _33, _34, _41, _42, _43, _44};
   1774  }
   1775  static Matrix4x4Typed FromUnknownMatrix(const UnknownMatrix& aUnknown) {
   1776    return Matrix4x4Typed{
   1777        aUnknown._11, aUnknown._12, aUnknown._13, aUnknown._14,
   1778        aUnknown._21, aUnknown._22, aUnknown._23, aUnknown._24,
   1779        aUnknown._31, aUnknown._32, aUnknown._33, aUnknown._34,
   1780        aUnknown._41, aUnknown._42, aUnknown._43, aUnknown._44};
   1781  }
   1782  /**
   1783   * For convenience, overload FromUnknownMatrix() for Maybe<Matrix>.
   1784   */
   1785  static Maybe<Matrix4x4Typed> FromUnknownMatrix(
   1786      const Maybe<UnknownMatrix>& aUnknown) {
   1787    if (aUnknown.isSome()) {
   1788      return Some(FromUnknownMatrix(*aUnknown));
   1789    }
   1790    return Nothing();
   1791  }
   1792 };
   1793 
   1794 typedef Matrix4x4Typed<UnknownUnits, UnknownUnits> Matrix4x4;
   1795 typedef Matrix4x4Typed<UnknownUnits, UnknownUnits, double> Matrix4x4Double;
   1796 
   1797 class Matrix5x4 {
   1798 public:
   1799  Matrix5x4()
   1800      : _11(1.0f),
   1801        _12(0),
   1802        _13(0),
   1803        _14(0),
   1804        _21(0),
   1805        _22(1.0f),
   1806        _23(0),
   1807        _24(0),
   1808        _31(0),
   1809        _32(0),
   1810        _33(1.0f),
   1811        _34(0),
   1812        _41(0),
   1813        _42(0),
   1814        _43(0),
   1815        _44(1.0f),
   1816        _51(0),
   1817        _52(0),
   1818        _53(0),
   1819        _54(0) {}
   1820  Matrix5x4(Float a11, Float a12, Float a13, Float a14, Float a21, Float a22,
   1821            Float a23, Float a24, Float a31, Float a32, Float a33, Float a34,
   1822            Float a41, Float a42, Float a43, Float a44, Float a51, Float a52,
   1823            Float a53, Float a54)
   1824      : _11(a11),
   1825        _12(a12),
   1826        _13(a13),
   1827        _14(a14),
   1828        _21(a21),
   1829        _22(a22),
   1830        _23(a23),
   1831        _24(a24),
   1832        _31(a31),
   1833        _32(a32),
   1834        _33(a33),
   1835        _34(a34),
   1836        _41(a41),
   1837        _42(a42),
   1838        _43(a43),
   1839        _44(a44),
   1840        _51(a51),
   1841        _52(a52),
   1842        _53(a53),
   1843        _54(a54) {}
   1844 
   1845  bool operator==(const Matrix5x4& o) const {
   1846    return _11 == o._11 && _12 == o._12 && _13 == o._13 && _14 == o._14 &&
   1847           _21 == o._21 && _22 == o._22 && _23 == o._23 && _24 == o._24 &&
   1848           _31 == o._31 && _32 == o._32 && _33 == o._33 && _34 == o._34 &&
   1849           _41 == o._41 && _42 == o._42 && _43 == o._43 && _44 == o._44 &&
   1850           _51 == o._51 && _52 == o._52 && _53 == o._53 && _54 == o._54;
   1851  }
   1852 
   1853  bool operator!=(const Matrix5x4& aMatrix) const {
   1854    return !(*this == aMatrix);
   1855  }
   1856 
   1857  Matrix5x4 operator*(const Matrix5x4& aMatrix) const {
   1858    Matrix5x4 resultMatrix;
   1859 
   1860    resultMatrix._11 = this->_11 * aMatrix._11 + this->_12 * aMatrix._21 +
   1861                       this->_13 * aMatrix._31 + this->_14 * aMatrix._41;
   1862    resultMatrix._12 = this->_11 * aMatrix._12 + this->_12 * aMatrix._22 +
   1863                       this->_13 * aMatrix._32 + this->_14 * aMatrix._42;
   1864    resultMatrix._13 = this->_11 * aMatrix._13 + this->_12 * aMatrix._23 +
   1865                       this->_13 * aMatrix._33 + this->_14 * aMatrix._43;
   1866    resultMatrix._14 = this->_11 * aMatrix._14 + this->_12 * aMatrix._24 +
   1867                       this->_13 * aMatrix._34 + this->_14 * aMatrix._44;
   1868    resultMatrix._21 = this->_21 * aMatrix._11 + this->_22 * aMatrix._21 +
   1869                       this->_23 * aMatrix._31 + this->_24 * aMatrix._41;
   1870    resultMatrix._22 = this->_21 * aMatrix._12 + this->_22 * aMatrix._22 +
   1871                       this->_23 * aMatrix._32 + this->_24 * aMatrix._42;
   1872    resultMatrix._23 = this->_21 * aMatrix._13 + this->_22 * aMatrix._23 +
   1873                       this->_23 * aMatrix._33 + this->_24 * aMatrix._43;
   1874    resultMatrix._24 = this->_21 * aMatrix._14 + this->_22 * aMatrix._24 +
   1875                       this->_23 * aMatrix._34 + this->_24 * aMatrix._44;
   1876    resultMatrix._31 = this->_31 * aMatrix._11 + this->_32 * aMatrix._21 +
   1877                       this->_33 * aMatrix._31 + this->_34 * aMatrix._41;
   1878    resultMatrix._32 = this->_31 * aMatrix._12 + this->_32 * aMatrix._22 +
   1879                       this->_33 * aMatrix._32 + this->_34 * aMatrix._42;
   1880    resultMatrix._33 = this->_31 * aMatrix._13 + this->_32 * aMatrix._23 +
   1881                       this->_33 * aMatrix._33 + this->_34 * aMatrix._43;
   1882    resultMatrix._34 = this->_31 * aMatrix._14 + this->_32 * aMatrix._24 +
   1883                       this->_33 * aMatrix._34 + this->_34 * aMatrix._44;
   1884    resultMatrix._41 = this->_41 * aMatrix._11 + this->_42 * aMatrix._21 +
   1885                       this->_43 * aMatrix._31 + this->_44 * aMatrix._41;
   1886    resultMatrix._42 = this->_41 * aMatrix._12 + this->_42 * aMatrix._22 +
   1887                       this->_43 * aMatrix._32 + this->_44 * aMatrix._42;
   1888    resultMatrix._43 = this->_41 * aMatrix._13 + this->_42 * aMatrix._23 +
   1889                       this->_43 * aMatrix._33 + this->_44 * aMatrix._43;
   1890    resultMatrix._44 = this->_41 * aMatrix._14 + this->_42 * aMatrix._24 +
   1891                       this->_43 * aMatrix._34 + this->_44 * aMatrix._44;
   1892    resultMatrix._51 = this->_51 * aMatrix._11 + this->_52 * aMatrix._21 +
   1893                       this->_53 * aMatrix._31 + this->_54 * aMatrix._41 +
   1894                       aMatrix._51;
   1895    resultMatrix._52 = this->_51 * aMatrix._12 + this->_52 * aMatrix._22 +
   1896                       this->_53 * aMatrix._32 + this->_54 * aMatrix._42 +
   1897                       aMatrix._52;
   1898    resultMatrix._53 = this->_51 * aMatrix._13 + this->_52 * aMatrix._23 +
   1899                       this->_53 * aMatrix._33 + this->_54 * aMatrix._43 +
   1900                       aMatrix._53;
   1901    resultMatrix._54 = this->_51 * aMatrix._14 + this->_52 * aMatrix._24 +
   1902                       this->_53 * aMatrix._34 + this->_54 * aMatrix._44 +
   1903                       aMatrix._54;
   1904 
   1905    return resultMatrix;
   1906  }
   1907 
   1908  Matrix5x4& operator*=(const Matrix5x4& aMatrix) {
   1909    *this = *this * aMatrix;
   1910    return *this;
   1911  }
   1912 
   1913  friend std::ostream& operator<<(std::ostream& aStream,
   1914                                  const Matrix5x4& aMatrix) {
   1915    const Float* f = &aMatrix._11;
   1916    aStream << "[ " << f[0] << ' ' << f[1] << ' ' << f[2] << ' ' << f[3] << ';';
   1917    f += 4;
   1918    aStream << ' ' << f[0] << ' ' << f[1] << ' ' << f[2] << ' ' << f[3] << ';';
   1919    f += 4;
   1920    aStream << ' ' << f[0] << ' ' << f[1] << ' ' << f[2] << ' ' << f[3] << ';';
   1921    f += 4;
   1922    aStream << ' ' << f[0] << ' ' << f[1] << ' ' << f[2] << ' ' << f[3] << ';';
   1923    f += 4;
   1924    aStream << ' ' << f[0] << ' ' << f[1] << ' ' << f[2] << ' ' << f[3]
   1925            << "; ]";
   1926    return aStream;
   1927  }
   1928 
   1929  union {
   1930    struct {
   1931      Float _11, _12, _13, _14;
   1932      Float _21, _22, _23, _24;
   1933      Float _31, _32, _33, _34;
   1934      Float _41, _42, _43, _44;
   1935      Float _51, _52, _53, _54;
   1936    };
   1937    Float components[20];
   1938  };
   1939 };
   1940 
   1941 /* This Matrix class will carry one additional type field in order to
   1942 * track what type of 4x4 matrix we're dealing with, it can then execute
   1943 * simplified versions of certain operations when applicable.
   1944 * This does not allow access to the parent class directly, as a caller
   1945 * could then mutate the parent class without updating the type.
   1946 */
   1947 
   1948 enum class MatrixType : uint8_t {
   1949  Identity,
   1950  Simple,  // 2x3 Matrix
   1951  Full     // 4x4 Matrix
   1952 };
   1953 
   1954 template <typename SourceUnits, typename TargetUnits>
   1955 class Matrix4x4TypedFlagged
   1956    : protected Matrix4x4Typed<SourceUnits, TargetUnits> {
   1957 public:
   1958  using Parent = Matrix4x4Typed<SourceUnits, TargetUnits>;
   1959  using Parent::_11;
   1960  using Parent::_12;
   1961  using Parent::_13;
   1962  using Parent::_14;
   1963  using Parent::_21;
   1964  using Parent::_22;
   1965  using Parent::_23;
   1966  using Parent::_24;
   1967  using Parent::_31;
   1968  using Parent::_32;
   1969  using Parent::_33;
   1970  using Parent::_34;
   1971  using Parent::_41;
   1972  using Parent::_42;
   1973  using Parent::_43;
   1974  using Parent::_44;
   1975 
   1976  Matrix4x4TypedFlagged() : mType(MatrixType::Identity) {}
   1977 
   1978  Matrix4x4TypedFlagged(Float a11, Float a12, Float a13, Float a14, Float a21,
   1979                        Float a22, Float a23, Float a24, Float a31, Float a32,
   1980                        Float a33, Float a34, Float a41, Float a42, Float a43,
   1981                        Float a44)
   1982      : Parent(a11, a12, a13, a14, a21, a22, a23, a24, a31, a32, a33, a34, a41,
   1983               a42, a43, a44) {
   1984    Analyze();
   1985  }
   1986 
   1987  MOZ_IMPLICIT Matrix4x4TypedFlagged(const Parent& aOther) : Parent(aOther) {
   1988    Analyze();
   1989  }
   1990 
   1991  template <typename NewMatrix4x4TypedFlagged>
   1992  [[nodiscard]] NewMatrix4x4TypedFlagged Cast() const {
   1993    return NewMatrix4x4TypedFlagged(_11, _12, _13, _14, _21, _22, _23, _24, _31,
   1994                                    _32, _33, _34, _41, _42, _43, _44, mType);
   1995  }
   1996 
   1997  static Matrix4x4TypedFlagged Translation2d(Float aX, Float aY) {
   1998    MatrixType matrixType = MatrixType::Simple;
   1999    if (aX == 0.0 && aY == 0.0) {
   2000      matrixType = MatrixType::Identity;
   2001    }
   2002    return Matrix4x4TypedFlagged(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
   2003                                 0.0f, 0.0f, 1.0f, 0.0f, aX, aY, 0.0f, 1.0f,
   2004                                 matrixType);
   2005  }
   2006 
   2007  static Matrix4x4TypedFlagged Scaling(Float aScaleX, Float aScaleY,
   2008                                       Float aScaleZ) {
   2009    MatrixType matrixType = MatrixType::Full;
   2010    if (aScaleZ == 1.0) {
   2011      if (aScaleX == 1.0 && aScaleY == 1.0) {
   2012        matrixType = MatrixType::Identity;
   2013      } else {
   2014        matrixType = MatrixType::Simple;
   2015      }
   2016    }
   2017    return Matrix4x4TypedFlagged(aScaleX, 0.0f, 0.0f, 0.0f, 0.0f, aScaleY, 0.0f,
   2018                                 0.0f, 0.0f, 0.0f, aScaleZ, 0.0f, 0.0f, 0.0f,
   2019                                 0.0f, 1.0f, matrixType);
   2020  }
   2021 
   2022  template <class F>
   2023  PointTyped<TargetUnits, F> TransformPoint(
   2024      const PointTyped<SourceUnits, F>& aPoint) const {
   2025    if (mType == MatrixType::Identity) {
   2026      return aPoint;
   2027    }
   2028 
   2029    if (mType == MatrixType::Simple) {
   2030      return TransformPointSimple(aPoint);
   2031    }
   2032 
   2033    return Parent::TransformPoint(aPoint);
   2034  }
   2035 
   2036  template <class F>
   2037  RectTyped<TargetUnits, F> TransformBounds(
   2038      const RectTyped<SourceUnits, F>& aRect) const {
   2039    if (mType == MatrixType::Identity) {
   2040      return aRect;
   2041    }
   2042 
   2043    if (mType == MatrixType::Simple) {
   2044      PointTyped<TargetUnits, F> quad[4];
   2045      F min_x, max_x;
   2046      F min_y, max_y;
   2047 
   2048      quad[0] = TransformPointSimple(aRect.TopLeft());
   2049      quad[1] = TransformPointSimple(aRect.TopRight());
   2050      quad[2] = TransformPointSimple(aRect.BottomLeft());
   2051      quad[3] = TransformPointSimple(aRect.BottomRight());
   2052 
   2053      min_x = max_x = quad[0].x;
   2054      min_y = max_y = quad[0].y;
   2055 
   2056      for (int i = 1; i < 4; i++) {
   2057        if (quad[i].x < min_x) {
   2058          min_x = quad[i].x;
   2059        }
   2060        if (quad[i].x > max_x) {
   2061          max_x = quad[i].x;
   2062        }
   2063 
   2064        if (quad[i].y < min_y) {
   2065          min_y = quad[i].y;
   2066        }
   2067        if (quad[i].y > max_y) {
   2068          max_y = quad[i].y;
   2069        }
   2070      }
   2071 
   2072      return RectTyped<TargetUnits, F>(min_x, min_y, max_x - min_x,
   2073                                       max_y - min_y);
   2074    }
   2075 
   2076    return Parent::TransformBounds(aRect);
   2077  }
   2078 
   2079  template <class F>
   2080  RectTyped<TargetUnits, F> TransformAndClipBounds(
   2081      const RectTyped<SourceUnits, F>& aRect,
   2082      const RectTyped<TargetUnits, F>& aClip) const {
   2083    if (mType == MatrixType::Identity) {
   2084      const RectTyped<SourceUnits, F>& clipped = aRect.Intersect(aClip);
   2085      return RectTyped<TargetUnits, F>(clipped.X(), clipped.Y(),
   2086                                       clipped.Width(), clipped.Height());
   2087    }
   2088 
   2089    if (mType == MatrixType::Simple) {
   2090      PointTyped<UnknownUnits, F> p1 = TransformPointSimple(aRect.TopLeft());
   2091      PointTyped<UnknownUnits, F> p2 = TransformPointSimple(aRect.TopRight());
   2092      PointTyped<UnknownUnits, F> p3 = TransformPointSimple(aRect.BottomLeft());
   2093      PointTyped<UnknownUnits, F> p4 =
   2094          TransformPointSimple(aRect.BottomRight());
   2095 
   2096      F min_x = std::min(std::min(std::min(p1.x, p2.x), p3.x), p4.x);
   2097      F max_x = std::max(std::max(std::max(p1.x, p2.x), p3.x), p4.x);
   2098      F min_y = std::min(std::min(std::min(p1.y, p2.y), p3.y), p4.y);
   2099      F max_y = std::max(std::max(std::max(p1.y, p2.y), p3.y), p4.y);
   2100 
   2101      PointTyped<TargetUnits, F> topLeft(
   2102          std::min(std::max(min_x, aClip.x), aClip.XMost()),
   2103          std::min(std::max(min_y, aClip.y), aClip.YMost()));
   2104      F width = std::min(std::max(max_x, aClip.x), aClip.XMost()) - topLeft.x;
   2105      F height = std::min(std::max(max_y, aClip.y), aClip.YMost()) - topLeft.y;
   2106 
   2107      return RectTyped<TargetUnits, F>(topLeft.x, topLeft.y, width, height);
   2108    }
   2109    return Parent::TransformAndClipBounds(aRect, aClip);
   2110  }
   2111 
   2112  bool FuzzyEqual(const Parent& o) const { return Parent::FuzzyEqual(o); }
   2113 
   2114  bool FuzzyEqual(const Matrix4x4TypedFlagged& o) const {
   2115    if (mType == MatrixType::Identity && o.mType == MatrixType::Identity) {
   2116      return true;
   2117    }
   2118    return Parent::FuzzyEqual(o);
   2119  }
   2120 
   2121  Matrix4x4TypedFlagged& PreTranslate(Float aX, Float aY, Float aZ) {
   2122    if (mType == MatrixType::Identity) {
   2123      _41 = aX;
   2124      _42 = aY;
   2125      _43 = aZ;
   2126 
   2127      if (!aZ) {
   2128        mType = MatrixType::Simple;
   2129        return *this;
   2130      }
   2131      mType = MatrixType::Full;
   2132      return *this;
   2133    }
   2134 
   2135    Parent::PreTranslate(aX, aY, aZ);
   2136 
   2137    if (aZ != 0) {
   2138      mType = MatrixType::Full;
   2139    }
   2140 
   2141    return *this;
   2142  }
   2143 
   2144  Matrix4x4TypedFlagged& PostTranslate(Float aX, Float aY, Float aZ) {
   2145    if (mType == MatrixType::Identity) {
   2146      _41 = aX;
   2147      _42 = aY;
   2148      _43 = aZ;
   2149 
   2150      if (!aZ) {
   2151        mType = MatrixType::Simple;
   2152        return *this;
   2153      }
   2154      mType = MatrixType::Full;
   2155      return *this;
   2156    }
   2157 
   2158    Parent::PostTranslate(aX, aY, aZ);
   2159 
   2160    if (aZ != 0) {
   2161      mType = MatrixType::Full;
   2162    }
   2163 
   2164    return *this;
   2165  }
   2166 
   2167  Matrix4x4TypedFlagged& ChangeBasis(Float aX, Float aY, Float aZ) {
   2168    // Translate to the origin before applying this matrix
   2169    PreTranslate(-aX, -aY, -aZ);
   2170 
   2171    // Translate back into position after applying this matrix
   2172    PostTranslate(aX, aY, aZ);
   2173 
   2174    return *this;
   2175  }
   2176 
   2177  bool IsIdentity() const { return mType == MatrixType::Identity; }
   2178 
   2179  template <class F>
   2180  Point4DTyped<TargetUnits, F> ProjectPoint(
   2181      const PointTyped<SourceUnits, F>& aPoint) const {
   2182    if (mType == MatrixType::Identity) {
   2183      return Point4DTyped<TargetUnits, F>(aPoint.x, aPoint.y, 0, 1);
   2184    }
   2185 
   2186    if (mType == MatrixType::Simple) {
   2187      PointTyped<TargetUnits, F> point = TransformPointSimple(aPoint);
   2188      return Point4DTyped<TargetUnits, F>(point.x, point.y, 0, 1);
   2189    }
   2190 
   2191    return Parent::ProjectPoint(aPoint);
   2192  }
   2193 
   2194  Matrix4x4TypedFlagged& ProjectTo2D() {
   2195    if (mType == MatrixType::Full) {
   2196      Parent::ProjectTo2D();
   2197    }
   2198    return *this;
   2199  }
   2200 
   2201  bool IsSingular() const {
   2202    if (mType == MatrixType::Identity) {
   2203      return false;
   2204    }
   2205    return Parent::Determinant() == 0.0;
   2206  }
   2207 
   2208  bool Invert() {
   2209    if (mType == MatrixType::Identity) {
   2210      return true;
   2211    }
   2212 
   2213    return Parent::Invert();
   2214  }
   2215 
   2216  Matrix4x4TypedFlagged<TargetUnits, SourceUnits> Inverse() const {
   2217    typedef Matrix4x4TypedFlagged<TargetUnits, SourceUnits> InvertedMatrix;
   2218    InvertedMatrix clone = Cast<InvertedMatrix>();
   2219    if (mType == MatrixType::Identity) {
   2220      return clone;
   2221    }
   2222    DebugOnly<bool> inverted = clone.Invert();
   2223    MOZ_ASSERT(inverted,
   2224               "Attempted to get the inverse of a non-invertible matrix");
   2225 
   2226    // Inverting a 2D Matrix should result in a 2D matrix, ergo mType doesn't
   2227    // change.
   2228    return clone;
   2229  }
   2230 
   2231  Maybe<Matrix4x4TypedFlagged<TargetUnits, SourceUnits>> MaybeInverse() const {
   2232    typedef Matrix4x4TypedFlagged<TargetUnits, SourceUnits> InvertedMatrix;
   2233    InvertedMatrix clone = Cast<InvertedMatrix>();
   2234    if (clone.Invert()) {
   2235      return Some(clone);
   2236    }
   2237    return Nothing();
   2238  }
   2239 
   2240  template <typename NewTargetUnits>
   2241  bool operator==(
   2242      const Matrix4x4TypedFlagged<TargetUnits, NewTargetUnits>& aMatrix) const {
   2243    if (mType == MatrixType::Identity &&
   2244        aMatrix.mType == MatrixType::Identity) {
   2245      return true;
   2246    }
   2247    // Depending on the usage it may make sense to compare more flags.
   2248    return Parent::operator==(aMatrix);
   2249  }
   2250 
   2251  template <typename NewTargetUnits>
   2252  bool operator!=(
   2253      const Matrix4x4TypedFlagged<TargetUnits, NewTargetUnits>& aMatrix) const {
   2254    if (mType == MatrixType::Identity &&
   2255        aMatrix.mType == MatrixType::Identity) {
   2256      return false;
   2257    }
   2258    // Depending on the usage it may make sense to compare more flags.
   2259    return Parent::operator!=(aMatrix);
   2260  }
   2261 
   2262  template <typename NewTargetUnits>
   2263  Matrix4x4TypedFlagged<SourceUnits, NewTargetUnits> operator*(
   2264      const Matrix4x4Typed<TargetUnits, NewTargetUnits>& aMatrix) const {
   2265    if (mType == MatrixType::Identity) {
   2266      return aMatrix;
   2267    }
   2268 
   2269    if (mType == MatrixType::Simple) {
   2270      Matrix4x4TypedFlagged<SourceUnits, NewTargetUnits> matrix;
   2271      matrix._11 = _11 * aMatrix._11 + _12 * aMatrix._21;
   2272      matrix._21 = _21 * aMatrix._11 + _22 * aMatrix._21;
   2273      matrix._31 = aMatrix._31;
   2274      matrix._41 = _41 * aMatrix._11 + _42 * aMatrix._21 + aMatrix._41;
   2275      matrix._12 = _11 * aMatrix._12 + _12 * aMatrix._22;
   2276      matrix._22 = _21 * aMatrix._12 + _22 * aMatrix._22;
   2277      matrix._32 = aMatrix._32;
   2278      matrix._42 = _41 * aMatrix._12 + _42 * aMatrix._22 + aMatrix._42;
   2279      matrix._13 = _11 * aMatrix._13 + _12 * aMatrix._23;
   2280      matrix._23 = _21 * aMatrix._13 + _22 * aMatrix._23;
   2281      matrix._33 = aMatrix._33;
   2282      matrix._43 = _41 * aMatrix._13 + _42 * aMatrix._23 + aMatrix._43;
   2283      matrix._14 = _11 * aMatrix._14 + _12 * aMatrix._24;
   2284      matrix._24 = _21 * aMatrix._14 + _22 * aMatrix._24;
   2285      matrix._34 = aMatrix._34;
   2286      matrix._44 = _41 * aMatrix._14 + _42 * aMatrix._24 + aMatrix._44;
   2287      matrix.Analyze();
   2288      return matrix;
   2289    }
   2290 
   2291    return Parent::operator*(aMatrix);
   2292  }
   2293 
   2294  template <typename NewTargetUnits>
   2295  Matrix4x4TypedFlagged<SourceUnits, NewTargetUnits> operator*(
   2296      const Matrix4x4TypedFlagged<TargetUnits, NewTargetUnits>& aMatrix) const {
   2297    if (mType == MatrixType::Identity) {
   2298      return aMatrix;
   2299    }
   2300 
   2301    if (aMatrix.mType == MatrixType::Identity) {
   2302      return Cast<Matrix4x4TypedFlagged<SourceUnits, NewTargetUnits>>();
   2303    }
   2304 
   2305    if (mType == MatrixType::Simple && aMatrix.mType == MatrixType::Simple) {
   2306      Matrix4x4TypedFlagged<SourceUnits, NewTargetUnits> matrix;
   2307      matrix._11 = _11 * aMatrix._11 + _12 * aMatrix._21;
   2308      matrix._21 = _21 * aMatrix._11 + _22 * aMatrix._21;
   2309      matrix._41 = _41 * aMatrix._11 + _42 * aMatrix._21 + aMatrix._41;
   2310      matrix._12 = _11 * aMatrix._12 + _12 * aMatrix._22;
   2311      matrix._22 = _21 * aMatrix._12 + _22 * aMatrix._22;
   2312      matrix._42 = _41 * aMatrix._12 + _42 * aMatrix._22 + aMatrix._42;
   2313      matrix.mType = MatrixType::Simple;
   2314      return matrix;
   2315    } else if (mType == MatrixType::Simple) {
   2316      Matrix4x4TypedFlagged<SourceUnits, NewTargetUnits> matrix;
   2317      matrix._11 = _11 * aMatrix._11 + _12 * aMatrix._21;
   2318      matrix._21 = _21 * aMatrix._11 + _22 * aMatrix._21;
   2319      matrix._31 = aMatrix._31;
   2320      matrix._41 = _41 * aMatrix._11 + _42 * aMatrix._21 + aMatrix._41;
   2321      matrix._12 = _11 * aMatrix._12 + _12 * aMatrix._22;
   2322      matrix._22 = _21 * aMatrix._12 + _22 * aMatrix._22;
   2323      matrix._32 = aMatrix._32;
   2324      matrix._42 = _41 * aMatrix._12 + _42 * aMatrix._22 + aMatrix._42;
   2325      matrix._13 = _11 * aMatrix._13 + _12 * aMatrix._23;
   2326      matrix._23 = _21 * aMatrix._13 + _22 * aMatrix._23;
   2327      matrix._33 = aMatrix._33;
   2328      matrix._43 = _41 * aMatrix._13 + _42 * aMatrix._23 + aMatrix._43;
   2329      matrix._14 = _11 * aMatrix._14 + _12 * aMatrix._24;
   2330      matrix._24 = _21 * aMatrix._14 + _22 * aMatrix._24;
   2331      matrix._34 = aMatrix._34;
   2332      matrix._44 = _41 * aMatrix._14 + _42 * aMatrix._24 + aMatrix._44;
   2333      matrix.mType = MatrixType::Full;
   2334      return matrix;
   2335    } else if (aMatrix.mType == MatrixType::Simple) {
   2336      Matrix4x4TypedFlagged<SourceUnits, NewTargetUnits> matrix;
   2337      matrix._11 = _11 * aMatrix._11 + _12 * aMatrix._21 + _14 * aMatrix._41;
   2338      matrix._21 = _21 * aMatrix._11 + _22 * aMatrix._21 + _24 * aMatrix._41;
   2339      matrix._31 = _31 * aMatrix._11 + _32 * aMatrix._21 + _34 * aMatrix._41;
   2340      matrix._41 = _41 * aMatrix._11 + _42 * aMatrix._21 + _44 * aMatrix._41;
   2341      matrix._12 = _11 * aMatrix._12 + _12 * aMatrix._22 + _14 * aMatrix._42;
   2342      matrix._22 = _21 * aMatrix._12 + _22 * aMatrix._22 + _24 * aMatrix._42;
   2343      matrix._32 = _31 * aMatrix._12 + _32 * aMatrix._22 + _34 * aMatrix._42;
   2344      matrix._42 = _41 * aMatrix._12 + _42 * aMatrix._22 + _44 * aMatrix._42;
   2345      matrix._13 = _13;
   2346      matrix._23 = _23;
   2347      matrix._33 = _33;
   2348      matrix._43 = _43;
   2349      matrix._14 = _14;
   2350      matrix._24 = _24;
   2351      matrix._34 = _34;
   2352      matrix._44 = _44;
   2353      matrix.mType = MatrixType::Full;
   2354      return matrix;
   2355    }
   2356 
   2357    return Parent::operator*(aMatrix);
   2358  }
   2359 
   2360  bool Is2D() const { return mType != MatrixType::Full; }
   2361 
   2362  bool CanDraw2D(Matrix* aMatrix = nullptr) const {
   2363    if (mType != MatrixType::Full) {
   2364      if (aMatrix) {
   2365        aMatrix->_11 = _11;
   2366        aMatrix->_12 = _12;
   2367        aMatrix->_21 = _21;
   2368        aMatrix->_22 = _22;
   2369        aMatrix->_31 = _41;
   2370        aMatrix->_32 = _42;
   2371      }
   2372      return true;
   2373    }
   2374    return Parent::CanDraw2D(aMatrix);
   2375  }
   2376 
   2377  bool Is2D(Matrix* aMatrix) const {
   2378    if (!Is2D()) {
   2379      return false;
   2380    }
   2381    if (aMatrix) {
   2382      aMatrix->_11 = _11;
   2383      aMatrix->_12 = _12;
   2384      aMatrix->_21 = _21;
   2385      aMatrix->_22 = _22;
   2386      aMatrix->_31 = _41;
   2387      aMatrix->_32 = _42;
   2388    }
   2389    return true;
   2390  }
   2391 
   2392  template <class F>
   2393  RectTyped<TargetUnits, F> ProjectRectBounds(
   2394      const RectTyped<SourceUnits, F>& aRect,
   2395      const RectTyped<TargetUnits, F>& aClip) const {
   2396    return Parent::ProjectRectBounds(aRect, aClip);
   2397  }
   2398 
   2399  const Parent& GetMatrix() const { return *this; }
   2400 
   2401  Matrix4x4Flagged ToUnknownMatrix() const {
   2402    return Matrix4x4Flagged{_11, _12, _13, _14, _21, _22, _23, _24,  _31,
   2403                            _32, _33, _34, _41, _42, _43, _44, mType};
   2404  }
   2405 
   2406  static Matrix4x4TypedFlagged FromUnknownMatrix(
   2407      const Matrix4x4Flagged& aUnknown) {
   2408    return Matrix4x4TypedFlagged{
   2409        aUnknown._11, aUnknown._12,  aUnknown._13, aUnknown._14, aUnknown._21,
   2410        aUnknown._22, aUnknown._23,  aUnknown._24, aUnknown._31, aUnknown._32,
   2411        aUnknown._33, aUnknown._34,  aUnknown._41, aUnknown._42, aUnknown._43,
   2412        aUnknown._44, aUnknown.mType};
   2413  }
   2414 
   2415 private:
   2416  Matrix4x4TypedFlagged(Float a11, Float a12, Float a13, Float a14, Float a21,
   2417                        Float a22, Float a23, Float a24, Float a31, Float a32,
   2418                        Float a33, Float a34, Float a41, Float a42, Float a43,
   2419                        Float a44, const MatrixType aType)
   2420      : Parent(a11, a12, a13, a14, a21, a22, a23, a24, a31, a32, a33, a34, a41,
   2421               a42, a43, a44),
   2422        mType(aType) {}
   2423 
   2424  template <class F>
   2425  PointTyped<TargetUnits, F> TransformPointSimple(
   2426      const PointTyped<SourceUnits, F>& aPoint) const {
   2427    PointTyped<SourceUnits, F> temp;
   2428    temp.x = aPoint.x * _11 + aPoint.y * _21 + _41;
   2429    temp.y = aPoint.x * _12 + aPoint.y * _22 + _42;
   2430    return temp;
   2431  }
   2432 
   2433  void Analyze() {
   2434    if (Parent::IsIdentity()) {
   2435      mType = MatrixType::Identity;
   2436      return;
   2437    }
   2438 
   2439    if (Parent::Is2D()) {
   2440      mType = MatrixType::Simple;
   2441      return;
   2442    }
   2443 
   2444    mType = MatrixType::Full;
   2445  }
   2446 
   2447  MatrixType mType;
   2448 
   2449  template <typename, typename>
   2450  friend class Matrix4x4TypedFlagged;
   2451 };
   2452 
   2453 using Matrix4x4Flagged = Matrix4x4TypedFlagged<UnknownUnits, UnknownUnits>;
   2454 
   2455 }  // namespace gfx
   2456 }  // namespace mozilla
   2457 
   2458 #endif /* MOZILLA_GFX_MATRIX_H_ */