|
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_ */ |