gfx/2d/Matrix.h

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:561ea906396b
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 "Rect.h"
11 #include "Point.h"
12 #include <math.h>
13
14 namespace mozilla {
15 namespace gfx {
16
17 class Matrix
18 {
19 public:
20 Matrix()
21 : _11(1.0f), _12(0)
22 , _21(0), _22(1.0f)
23 , _31(0), _32(0)
24 {}
25 Matrix(Float a11, Float a12, Float a21, Float a22, Float a31, Float a32)
26 : _11(a11), _12(a12)
27 , _21(a21), _22(a22)
28 , _31(a31), _32(a32)
29 {}
30 Float _11, _12;
31 Float _21, _22;
32 Float _31, _32;
33
34 Point operator *(const Point &aPoint) const
35 {
36 Point retPoint;
37
38 retPoint.x = aPoint.x * _11 + aPoint.y * _21 + _31;
39 retPoint.y = aPoint.x * _12 + aPoint.y * _22 + _32;
40
41 return retPoint;
42 }
43
44 Size operator *(const Size &aSize) const
45 {
46 Size retSize;
47
48 retSize.width = aSize.width * _11 + aSize.height * _21;
49 retSize.height = aSize.width * _12 + aSize.height * _22;
50
51 return retSize;
52 }
53
54 GFX2D_API Rect TransformBounds(const Rect& rect) const;
55
56 // Apply a scale to this matrix. This scale will be applied -before- the
57 // existing transformation of the matrix.
58 Matrix &Scale(Float aX, Float aY)
59 {
60 _11 *= aX;
61 _12 *= aX;
62 _21 *= aY;
63 _22 *= aY;
64
65 return *this;
66 }
67
68 Matrix &Translate(Float aX, Float aY)
69 {
70 _31 += _11 * aX + _21 * aY;
71 _32 += _12 * aX + _22 * aY;
72
73 return *this;
74 }
75
76 Matrix &PostTranslate(Float aX, Float aY)
77 {
78 _31 += aX;
79 _32 += aY;
80 return *this;
81 }
82
83 Matrix &Rotate(Float aAngle)
84 {
85 return *this = Matrix::Rotation(aAngle) * *this;
86 }
87
88 bool Invert()
89 {
90 // Compute co-factors.
91 Float A = _22;
92 Float B = -_21;
93 Float C = _21 * _32 - _22 * _31;
94 Float D = -_12;
95 Float E = _11;
96 Float F = _31 * _12 - _11 * _32;
97
98 Float det = Determinant();
99
100 if (!det) {
101 return false;
102 }
103
104 Float inv_det = 1 / det;
105
106 _11 = inv_det * A;
107 _12 = inv_det * D;
108 _21 = inv_det * B;
109 _22 = inv_det * E;
110 _31 = inv_det * C;
111 _32 = inv_det * F;
112
113 return true;
114 }
115
116 Float Determinant() const
117 {
118 return _11 * _22 - _12 * _21;
119 }
120
121 static Matrix Translation(Float aX, Float aY)
122 {
123 return Matrix(1.0f, 0.0f, 0.0f, 1.0f, aX, aY);
124 }
125
126 static Matrix Translation(Point aPoint)
127 {
128 return Translation(aPoint.x, aPoint.y);
129 }
130
131 GFX2D_API static Matrix Rotation(Float aAngle);
132
133 static Matrix Scaling(Float aX, Float aY)
134 {
135 return Matrix(aX, 0.0f, 0.0f, aY, 0.0f, 0.0f);
136 }
137
138 Matrix operator*(const Matrix &aMatrix) const
139 {
140 Matrix resultMatrix;
141
142 resultMatrix._11 = this->_11 * aMatrix._11 + this->_12 * aMatrix._21;
143 resultMatrix._12 = this->_11 * aMatrix._12 + this->_12 * aMatrix._22;
144 resultMatrix._21 = this->_21 * aMatrix._11 + this->_22 * aMatrix._21;
145 resultMatrix._22 = this->_21 * aMatrix._12 + this->_22 * aMatrix._22;
146 resultMatrix._31 = this->_31 * aMatrix._11 + this->_32 * aMatrix._21 + aMatrix._31;
147 resultMatrix._32 = this->_31 * aMatrix._12 + this->_32 * aMatrix._22 + aMatrix._32;
148
149 return resultMatrix;
150 }
151
152 Matrix& operator*=(const Matrix &aMatrix)
153 {
154 Matrix resultMatrix = *this * aMatrix;
155 return *this = resultMatrix;
156 }
157
158 /* Returns true if the other matrix is fuzzy-equal to this matrix.
159 * Note that this isn't a cheap comparison!
160 */
161 bool operator==(const Matrix& other) const
162 {
163 return FuzzyEqual(_11, other._11) && FuzzyEqual(_12, other._12) &&
164 FuzzyEqual(_21, other._21) && FuzzyEqual(_22, other._22) &&
165 FuzzyEqual(_31, other._31) && FuzzyEqual(_32, other._32);
166 }
167
168 bool operator!=(const Matrix& other) const
169 {
170 return !(*this == other);
171 }
172
173 /* Returns true if the matrix is a rectilinear transformation (i.e.
174 * grid-aligned rectangles are transformed to grid-aligned rectangles)
175 */
176 bool IsRectilinear() const {
177 if (FuzzyEqual(_12, 0) && FuzzyEqual(_21, 0)) {
178 return true;
179 } else if (FuzzyEqual(_22, 0) && FuzzyEqual(_11, 0)) {
180 return true;
181 }
182
183 return false;
184 }
185
186 /**
187 * Returns true if the matrix is anything other than a straight
188 * translation by integers.
189 */
190 bool HasNonIntegerTranslation() const {
191 return HasNonTranslation() ||
192 !FuzzyEqual(_31, floor(_31 + 0.5)) ||
193 !FuzzyEqual(_32, floor(_32 + 0.5));
194 }
195
196 /**
197 * Returns true if the matrix has any transform other
198 * than a straight translation.
199 */
200 bool HasNonTranslation() const {
201 return !FuzzyEqual(_11, 1.0) || !FuzzyEqual(_22, 1.0) ||
202 !FuzzyEqual(_12, 0.0) || !FuzzyEqual(_21, 0.0);
203 }
204
205 /* Returns true if the matrix is an identity matrix.
206 */
207 bool IsIdentity() const
208 {
209 return _11 == 1.0f && _12 == 0.0f &&
210 _21 == 0.0f && _22 == 1.0f &&
211 _31 == 0.0f && _32 == 0.0f;
212 }
213
214 /* Returns true if the matrix is singular.
215 */
216 bool IsSingular() const
217 {
218 return Determinant() == 0;
219 }
220
221 GFX2D_API void NudgeToIntegers();
222
223 bool IsTranslation() const
224 {
225 return FuzzyEqual(_11, 1.0f) && FuzzyEqual(_12, 0.0f) &&
226 FuzzyEqual(_21, 0.0f) && FuzzyEqual(_22, 1.0f);
227 }
228
229 bool IsIntegerTranslation() const
230 {
231 return IsTranslation() &&
232 FuzzyEqual(_31, floorf(_31 + 0.5f)) &&
233 FuzzyEqual(_32, floorf(_32 + 0.5f));
234 }
235
236 Point GetTranslation() const {
237 return Point(_31, _32);
238 }
239
240 /**
241 * Returns true if matrix is multiple of 90 degrees rotation with flipping,
242 * scaling and translation.
243 */
244 bool PreservesAxisAlignedRectangles() const {
245 return ((FuzzyEqual(_11, 0.0) && FuzzyEqual(_22, 0.0))
246 || (FuzzyEqual(_12, 0.0) && FuzzyEqual(_21, 0.0)));
247 }
248
249 /**
250 * Returns true if the matrix has any transform other
251 * than a translation or scale; this is, if there is
252 * no rotation.
253 */
254 bool HasNonAxisAlignedTransform() const {
255 return !FuzzyEqual(_21, 0.0) || !FuzzyEqual(_12, 0.0);
256 }
257
258 /**
259 * Returns true if the matrix has non-integer scale
260 */
261 bool HasNonIntegerScale() const {
262 return !FuzzyEqual(_11, floor(_11 + 0.5)) ||
263 !FuzzyEqual(_22, floor(_22 + 0.5));
264 }
265
266 private:
267 static bool FuzzyEqual(Float aV1, Float aV2) {
268 // XXX - Check if fabs does the smart thing and just negates the sign bit.
269 return fabs(aV2 - aV1) < 1e-6;
270 }
271 };
272
273 class Matrix4x4
274 {
275 public:
276 Matrix4x4()
277 : _11(1.0f), _12(0.0f), _13(0.0f), _14(0.0f)
278 , _21(0.0f), _22(1.0f), _23(0.0f), _24(0.0f)
279 , _31(0.0f), _32(0.0f), _33(1.0f), _34(0.0f)
280 , _41(0.0f), _42(0.0f), _43(0.0f), _44(1.0f)
281 {}
282
283 Float _11, _12, _13, _14;
284 Float _21, _22, _23, _24;
285 Float _31, _32, _33, _34;
286 Float _41, _42, _43, _44;
287
288 /**
289 * Returns true if the matrix is isomorphic to a 2D affine transformation.
290 */
291 bool Is2D() const
292 {
293 if (_13 != 0.0f || _14 != 0.0f ||
294 _23 != 0.0f || _24 != 0.0f ||
295 _31 != 0.0f || _32 != 0.0f || _33 != 1.0f || _34 != 0.0f ||
296 _43 != 0.0f || _44 != 1.0f) {
297 return false;
298 }
299 return true;
300 }
301
302 bool Is2D(Matrix* aMatrix) const {
303 if (!Is2D()) {
304 return false;
305 }
306 if (aMatrix) {
307 aMatrix->_11 = _11;
308 aMatrix->_12 = _12;
309 aMatrix->_21 = _21;
310 aMatrix->_22 = _22;
311 aMatrix->_31 = _41;
312 aMatrix->_32 = _42;
313 }
314 return true;
315 }
316
317 Matrix As2D() const
318 {
319 MOZ_ASSERT(Is2D(), "Matrix is not a 2D affine transform");
320
321 return Matrix(_11, _12, _21, _22, _41, _42);
322 }
323
324 bool CanDraw2D(Matrix* aMatrix = nullptr) const {
325 if (_14 != 0.0f ||
326 _24 != 0.0f ||
327 _44 != 1.0f) {
328 return false;
329 }
330 if (aMatrix) {
331 aMatrix->_11 = _11;
332 aMatrix->_12 = _12;
333 aMatrix->_21 = _21;
334 aMatrix->_22 = _22;
335 aMatrix->_31 = _41;
336 aMatrix->_32 = _42;
337 }
338 return true;
339 }
340
341 Matrix4x4& ProjectTo2D() {
342 _31 = 0.0f;
343 _32 = 0.0f;
344 _13 = 0.0f;
345 _23 = 0.0f;
346 _33 = 1.0f;
347 _43 = 0.0f;
348 _34 = 0.0f;
349 return *this;
350 }
351
352 static Matrix4x4 From2D(const Matrix &aMatrix) {
353 Matrix4x4 matrix;
354 matrix._11 = aMatrix._11;
355 matrix._12 = aMatrix._12;
356 matrix._21 = aMatrix._21;
357 matrix._22 = aMatrix._22;
358 matrix._41 = aMatrix._31;
359 matrix._42 = aMatrix._32;
360 return matrix;
361 }
362
363 bool Is2DIntegerTranslation() const
364 {
365 return Is2D() && As2D().IsIntegerTranslation();
366 }
367
368 Point4D operator *(const Point4D& aPoint) const
369 {
370 Point4D retPoint;
371
372 retPoint.x = aPoint.x * _11 + aPoint.y * _21 + aPoint.z * _31 + _41;
373 retPoint.y = aPoint.x * _12 + aPoint.y * _22 + aPoint.z * _32 + _42;
374 retPoint.z = aPoint.x * _13 + aPoint.y * _23 + aPoint.z * _33 + _43;
375 retPoint.w = aPoint.x * _14 + aPoint.y * _24 + aPoint.z * _34 + _44;
376
377 return retPoint;
378 }
379
380 Point3D operator *(const Point3D& aPoint) const
381 {
382 Point4D temp(aPoint.x, aPoint.y, aPoint.z, 1);
383
384 temp = *this * temp;
385 temp /= temp.w;
386
387 return Point3D(temp.x, temp.y, temp.z);
388 }
389
390 Point operator *(const Point &aPoint) const
391 {
392 Point4D temp(aPoint.x, aPoint.y, 0, 1);
393
394 temp = *this * temp;
395 temp /= temp.w;
396
397 return Point(temp.x, temp.y);
398 }
399
400 GFX2D_API Rect TransformBounds(const Rect& rect) const;
401
402 // Apply a scale to this matrix. This scale will be applied -before- the
403 // existing transformation of the matrix.
404 Matrix4x4 &Scale(Float aX, Float aY, Float aZ)
405 {
406 _11 *= aX;
407 _12 *= aX;
408 _13 *= aX;
409 _21 *= aY;
410 _22 *= aY;
411 _23 *= aY;
412 _31 *= aZ;
413 _32 *= aZ;
414 _33 *= aZ;
415
416 return *this;
417 }
418
419 Matrix4x4 &Translate(Float aX, Float aY, Float aZ)
420 {
421 _41 += aX * _11 + aY * _21 + aZ * _31;
422 _42 += aX * _12 + aY * _22 + aZ * _32;
423 _43 += aX * _13 + aY * _23 + aZ * _33;
424 _44 += aX * _14 + aY * _24 + aZ * _34;
425
426 return *this;
427 }
428
429 bool operator==(const Matrix4x4& o) const
430 {
431 // XXX would be nice to memcmp here, but that breaks IEEE 754 semantics
432 return _11 == o._11 && _12 == o._12 && _13 == o._13 && _14 == o._14 &&
433 _21 == o._21 && _22 == o._22 && _23 == o._23 && _24 == o._24 &&
434 _31 == o._31 && _32 == o._32 && _33 == o._33 && _34 == o._34 &&
435 _41 == o._41 && _42 == o._42 && _43 == o._43 && _44 == o._44;
436 }
437
438 bool operator!=(const Matrix4x4& o) const
439 {
440 return !((*this) == o);
441 }
442
443 Matrix4x4 operator*(const Matrix4x4 &aMatrix) const
444 {
445 Matrix4x4 matrix;
446
447 matrix._11 = _11 * aMatrix._11 + _12 * aMatrix._21 + _13 * aMatrix._31 + _14 * aMatrix._41;
448 matrix._21 = _21 * aMatrix._11 + _22 * aMatrix._21 + _23 * aMatrix._31 + _24 * aMatrix._41;
449 matrix._31 = _31 * aMatrix._11 + _32 * aMatrix._21 + _33 * aMatrix._31 + _34 * aMatrix._41;
450 matrix._41 = _41 * aMatrix._11 + _42 * aMatrix._21 + _43 * aMatrix._31 + _44 * aMatrix._41;
451 matrix._12 = _11 * aMatrix._12 + _12 * aMatrix._22 + _13 * aMatrix._32 + _14 * aMatrix._42;
452 matrix._22 = _21 * aMatrix._12 + _22 * aMatrix._22 + _23 * aMatrix._32 + _24 * aMatrix._42;
453 matrix._32 = _31 * aMatrix._12 + _32 * aMatrix._22 + _33 * aMatrix._32 + _34 * aMatrix._42;
454 matrix._42 = _41 * aMatrix._12 + _42 * aMatrix._22 + _43 * aMatrix._32 + _44 * aMatrix._42;
455 matrix._13 = _11 * aMatrix._13 + _12 * aMatrix._23 + _13 * aMatrix._33 + _14 * aMatrix._43;
456 matrix._23 = _21 * aMatrix._13 + _22 * aMatrix._23 + _23 * aMatrix._33 + _24 * aMatrix._43;
457 matrix._33 = _31 * aMatrix._13 + _32 * aMatrix._23 + _33 * aMatrix._33 + _34 * aMatrix._43;
458 matrix._43 = _41 * aMatrix._13 + _42 * aMatrix._23 + _43 * aMatrix._33 + _44 * aMatrix._43;
459 matrix._14 = _11 * aMatrix._14 + _12 * aMatrix._24 + _13 * aMatrix._34 + _14 * aMatrix._44;
460 matrix._24 = _21 * aMatrix._14 + _22 * aMatrix._24 + _23 * aMatrix._34 + _24 * aMatrix._44;
461 matrix._34 = _31 * aMatrix._14 + _32 * aMatrix._24 + _33 * aMatrix._34 + _34 * aMatrix._44;
462 matrix._44 = _41 * aMatrix._14 + _42 * aMatrix._24 + _43 * aMatrix._34 + _44 * aMatrix._44;
463
464 return matrix;
465 }
466
467
468 /* Returns true if the matrix is an identity matrix.
469 */
470 bool IsIdentity() const
471 {
472 return _11 == 1.0f && _12 == 0.0f && _13 == 0.0f && _14 == 0.0f &&
473 _21 == 0.0f && _22 == 1.0f && _23 == 0.0f && _24 == 0.0f &&
474 _31 == 0.0f && _32 == 0.0f && _33 == 1.0f && _34 == 0.0f &&
475 _41 == 0.0f && _42 == 0.0f && _43 == 0.0f && _44 == 1.0f;
476 }
477
478 bool IsSingular() const
479 {
480 return Determinant() == 0.0;
481 }
482
483 Float Determinant() const
484 {
485 return _14 * _23 * _32 * _41
486 - _13 * _24 * _32 * _41
487 - _14 * _22 * _33 * _41
488 + _12 * _24 * _33 * _41
489 + _13 * _22 * _34 * _41
490 - _12 * _23 * _34 * _41
491 - _14 * _23 * _31 * _42
492 + _13 * _24 * _31 * _42
493 + _14 * _21 * _33 * _42
494 - _11 * _24 * _33 * _42
495 - _13 * _21 * _34 * _42
496 + _11 * _23 * _34 * _42
497 + _14 * _22 * _31 * _43
498 - _12 * _24 * _31 * _43
499 - _14 * _21 * _32 * _43
500 + _11 * _24 * _32 * _43
501 + _12 * _21 * _34 * _43
502 - _11 * _22 * _34 * _43
503 - _13 * _22 * _31 * _44
504 + _12 * _23 * _31 * _44
505 + _13 * _21 * _32 * _44
506 - _11 * _23 * _32 * _44
507 - _12 * _21 * _33 * _44
508 + _11 * _22 * _33 * _44;
509 }
510
511 };
512
513 class Matrix5x4
514 {
515 public:
516 Matrix5x4()
517 : _11(1.0f), _12(0), _13(0), _14(0)
518 , _21(0), _22(1.0f), _23(0), _24(0)
519 , _31(0), _32(0), _33(1.0f), _34(0)
520 , _41(0), _42(0), _43(0), _44(1.0f)
521 , _51(0), _52(0), _53(0), _54(0)
522 {}
523 Matrix5x4(Float a11, Float a12, Float a13, Float a14,
524 Float a21, Float a22, Float a23, Float a24,
525 Float a31, Float a32, Float a33, Float a34,
526 Float a41, Float a42, Float a43, Float a44,
527 Float a51, Float a52, Float a53, Float a54)
528 : _11(a11), _12(a12), _13(a13), _14(a14)
529 , _21(a21), _22(a22), _23(a23), _24(a24)
530 , _31(a31), _32(a32), _33(a33), _34(a34)
531 , _41(a41), _42(a42), _43(a43), _44(a44)
532 , _51(a51), _52(a52), _53(a53), _54(a54)
533 {}
534 Float _11, _12, _13, _14;
535 Float _21, _22, _23, _24;
536 Float _31, _32, _33, _34;
537 Float _41, _42, _43, _44;
538 Float _51, _52, _53, _54;
539 };
540
541 }
542 }
543
544 #endif /* MOZILLA_GFX_MATRIX_H_ */

mercurial