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