Coverage Report

Created: 2018-09-25 14:53

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