1/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "include/core/SkMatrix44.h"
9#include <type_traits>
10#include <utility>
11
12// Copying SkMatrix44 byte-wise is performance-critical to Blink. This class is
13// contained in several Transform classes, which are copied multiple times
14// during the rendering life cycle. See crbug.com/938563 for reference.
15#if defined(SK_BUILD_FOR_WIN) || defined(SK_BUILD_FOR_MAC)
16// std::is_trivially_copyable is not supported for some older clang versions,
17// which (at least as of this patch) are in use for Chromecast.
18static_assert(std::is_trivially_copyable<SkMatrix44>::value,
19 "SkMatrix44 must be trivially copyable");
20#endif
21
22static inline bool eq4(const SkScalar* SK_RESTRICT a,
23 const SkScalar* SK_RESTRICT b) {
24 return (a[0] == b[0]) & (a[1] == b[1]) & (a[2] == b[2]) & (a[3] == b[3]);
25}
26
27bool SkMatrix44::operator==(const SkMatrix44& other) const {
28 if (this == &other) {
29 return true;
30 }
31
32 if (this->isIdentity() && other.isIdentity()) {
33 return true;
34 }
35
36 const SkScalar* SK_RESTRICT a = &fMat[0][0];
37 const SkScalar* SK_RESTRICT b = &other.fMat[0][0];
38
39#if 0
40 for (int i = 0; i < 16; ++i) {
41 if (a[i] != b[i]) {
42 return false;
43 }
44 }
45 return true;
46#else
47 // to reduce branch instructions, we compare 4 at a time.
48 // see bench/Matrix44Bench.cpp for test.
49 if (!eq4(&a[0], &b[0])) {
50 return false;
51 }
52 if (!eq4(&a[4], &b[4])) {
53 return false;
54 }
55 if (!eq4(&a[8], &b[8])) {
56 return false;
57 }
58 return eq4(&a[12], &b[12]);
59#endif
60}
61
62///////////////////////////////////////////////////////////////////////////////
63void SkMatrix44::recomputeTypeMask() {
64 if (0 != perspX() || 0 != perspY() || 0 != perspZ() || 1 != fMat[3][3]) {
65 fTypeMask = kTranslate_Mask | kScale_Mask | kAffine_Mask | kPerspective_Mask;
66 return;
67 }
68
69 TypeMask mask = kIdentity_Mask;
70 if (0 != transX() || 0 != transY() || 0 != transZ()) {
71 mask |= kTranslate_Mask;
72 }
73
74 if (1 != scaleX() || 1 != scaleY() || 1 != scaleZ()) {
75 mask |= kScale_Mask;
76 }
77
78 if (0 != fMat[1][0] || 0 != fMat[0][1] || 0 != fMat[0][2] ||
79 0 != fMat[2][0] || 0 != fMat[1][2] || 0 != fMat[2][1]) {
80 mask |= kAffine_Mask;
81 }
82 fTypeMask = mask;
83}
84
85///////////////////////////////////////////////////////////////////////////////
86
87void SkMatrix44::asColMajorf(float dst[]) const {
88 const SkScalar* src = &fMat[0][0];
89 for (int i = 0; i < 16; ++i) {
90 dst[i] = src[i];
91 }
92}
93
94void SkMatrix44::as3x4RowMajorf(float dst[]) const {
95 dst[0] = fMat[0][0]; dst[1] = fMat[1][0]; dst[2] = fMat[2][0]; dst[3] = fMat[3][0];
96 dst[4] = fMat[0][1]; dst[5] = fMat[1][1]; dst[6] = fMat[2][1]; dst[7] = fMat[3][1];
97 dst[8] = fMat[0][2]; dst[9] = fMat[1][2]; dst[10] = fMat[2][2]; dst[11] = fMat[3][2];
98}
99
100void SkMatrix44::asColMajord(double dst[]) const {
101 const SkScalar* src = &fMat[0][0];
102 for (int i = 0; i < 16; ++i) {
103 dst[i] = src[i];
104 }
105}
106
107void SkMatrix44::asRowMajorf(float dst[]) const {
108 const SkScalar* src = &fMat[0][0];
109 for (int i = 0; i < 4; ++i) {
110 dst[0] = float(src[0]);
111 dst[4] = float(src[1]);
112 dst[8] = float(src[2]);
113 dst[12] = float(src[3]);
114 src += 4;
115 dst += 1;
116 }
117}
118
119void SkMatrix44::asRowMajord(double dst[]) const {
120 const SkScalar* src = &fMat[0][0];
121 for (int i = 0; i < 4; ++i) {
122 dst[0] = src[0];
123 dst[4] = src[1];
124 dst[8] = src[2];
125 dst[12] = src[3];
126 src += 4;
127 dst += 1;
128 }
129}
130
131void SkMatrix44::setColMajorf(const float src[]) {
132 SkScalar* dst = &fMat[0][0];
133 for (int i = 0; i < 16; ++i) {
134 dst[i] = src[i];
135 }
136
137 this->recomputeTypeMask();
138}
139
140void SkMatrix44::setColMajord(const double src[]) {
141 SkScalar* dst = &fMat[0][0];
142 for (int i = 0; i < 16; ++i) {
143 dst[i] = SkScalar(src[i]);
144 }
145
146 this->recomputeTypeMask();
147}
148
149void SkMatrix44::setRowMajorf(const float src[]) {
150 SkScalar* dst = &fMat[0][0];
151 for (int i = 0; i < 4; ++i) {
152 dst[0] = src[0];
153 dst[4] = src[1];
154 dst[8] = src[2];
155 dst[12] = src[3];
156 src += 4;
157 dst += 1;
158 }
159 this->recomputeTypeMask();
160}
161
162void SkMatrix44::setRowMajord(const double src[]) {
163 SkScalar* dst = &fMat[0][0];
164 for (int i = 0; i < 4; ++i) {
165 dst[0] = SkScalar(src[0]);
166 dst[4] = SkScalar(src[1]);
167 dst[8] = SkScalar(src[2]);
168 dst[12] = SkScalar(src[3]);
169 src += 4;
170 dst += 1;
171 }
172 this->recomputeTypeMask();
173}
174
175///////////////////////////////////////////////////////////////////////////////
176
177const SkMatrix44& SkMatrix44::I() {
178 static constexpr SkMatrix44 gIdentity44(kIdentity_Constructor);
179 return gIdentity44;
180}
181
182void SkMatrix44::setIdentity() {
183 fMat[0][0] = 1;
184 fMat[0][1] = 0;
185 fMat[0][2] = 0;
186 fMat[0][3] = 0;
187 fMat[1][0] = 0;
188 fMat[1][1] = 1;
189 fMat[1][2] = 0;
190 fMat[1][3] = 0;
191 fMat[2][0] = 0;
192 fMat[2][1] = 0;
193 fMat[2][2] = 1;
194 fMat[2][3] = 0;
195 fMat[3][0] = 0;
196 fMat[3][1] = 0;
197 fMat[3][2] = 0;
198 fMat[3][3] = 1;
199 this->setTypeMask(kIdentity_Mask);
200}
201
202void SkMatrix44::set3x3(SkScalar m_00, SkScalar m_10, SkScalar m_20,
203 SkScalar m_01, SkScalar m_11, SkScalar m_21,
204 SkScalar m_02, SkScalar m_12, SkScalar m_22) {
205 fMat[0][0] = m_00; fMat[0][1] = m_10; fMat[0][2] = m_20; fMat[0][3] = 0;
206 fMat[1][0] = m_01; fMat[1][1] = m_11; fMat[1][2] = m_21; fMat[1][3] = 0;
207 fMat[2][0] = m_02; fMat[2][1] = m_12; fMat[2][2] = m_22; fMat[2][3] = 0;
208 fMat[3][0] = 0; fMat[3][1] = 0; fMat[3][2] = 0; fMat[3][3] = 1;
209 this->recomputeTypeMask();
210}
211
212void SkMatrix44::set3x3RowMajorf(const float src[]) {
213 fMat[0][0] = src[0]; fMat[0][1] = src[3]; fMat[0][2] = src[6]; fMat[0][3] = 0;
214 fMat[1][0] = src[1]; fMat[1][1] = src[4]; fMat[1][2] = src[7]; fMat[1][3] = 0;
215 fMat[2][0] = src[2]; fMat[2][1] = src[5]; fMat[2][2] = src[8]; fMat[2][3] = 0;
216 fMat[3][0] = 0; fMat[3][1] = 0; fMat[3][2] = 0; fMat[3][3] = 1;
217 this->recomputeTypeMask();
218}
219
220void SkMatrix44::set3x4RowMajorf(const float src[]) {
221 fMat[0][0] = src[0]; fMat[1][0] = src[1]; fMat[2][0] = src[2]; fMat[3][0] = src[3];
222 fMat[0][1] = src[4]; fMat[1][1] = src[5]; fMat[2][1] = src[6]; fMat[3][1] = src[7];
223 fMat[0][2] = src[8]; fMat[1][2] = src[9]; fMat[2][2] = src[10]; fMat[3][2] = src[11];
224 fMat[0][3] = 0; fMat[1][3] = 0; fMat[2][3] = 0; fMat[3][3] = 1;
225 this->recomputeTypeMask();
226}
227
228void SkMatrix44::set4x4(SkScalar m_00, SkScalar m_10, SkScalar m_20, SkScalar m_30,
229 SkScalar m_01, SkScalar m_11, SkScalar m_21, SkScalar m_31,
230 SkScalar m_02, SkScalar m_12, SkScalar m_22, SkScalar m_32,
231 SkScalar m_03, SkScalar m_13, SkScalar m_23, SkScalar m_33) {
232 fMat[0][0] = m_00; fMat[0][1] = m_10; fMat[0][2] = m_20; fMat[0][3] = m_30;
233 fMat[1][0] = m_01; fMat[1][1] = m_11; fMat[1][2] = m_21; fMat[1][3] = m_31;
234 fMat[2][0] = m_02; fMat[2][1] = m_12; fMat[2][2] = m_22; fMat[2][3] = m_32;
235 fMat[3][0] = m_03; fMat[3][1] = m_13; fMat[3][2] = m_23; fMat[3][3] = m_33;
236 this->recomputeTypeMask();
237}
238
239
240///////////////////////////////////////////////////////////////////////////////
241
242SkMatrix44& SkMatrix44::setTranslate(SkScalar dx, SkScalar dy, SkScalar dz) {
243 this->setIdentity();
244
245 if (!dx && !dy && !dz) {
246 return *this;
247 }
248
249 fMat[3][0] = dx;
250 fMat[3][1] = dy;
251 fMat[3][2] = dz;
252 this->setTypeMask(kTranslate_Mask);
253 return *this;
254}
255
256SkMatrix44& SkMatrix44::preTranslate(SkScalar dx, SkScalar dy, SkScalar dz) {
257 if (!dx && !dy && !dz) {
258 return *this;
259 }
260
261 for (int i = 0; i < 4; ++i) {
262 fMat[3][i] = fMat[0][i] * dx + fMat[1][i] * dy + fMat[2][i] * dz + fMat[3][i];
263 }
264 this->recomputeTypeMask();
265 return *this;
266}
267
268SkMatrix44& SkMatrix44::postTranslate(SkScalar dx, SkScalar dy, SkScalar dz) {
269 if (!dx && !dy && !dz) {
270 return *this;
271 }
272
273 if (this->getType() & kPerspective_Mask) {
274 for (int i = 0; i < 4; ++i) {
275 fMat[i][0] += fMat[i][3] * dx;
276 fMat[i][1] += fMat[i][3] * dy;
277 fMat[i][2] += fMat[i][3] * dz;
278 }
279 } else {
280 fMat[3][0] += dx;
281 fMat[3][1] += dy;
282 fMat[3][2] += dz;
283 this->recomputeTypeMask();
284 }
285 return *this;
286}
287
288///////////////////////////////////////////////////////////////////////////////
289
290SkMatrix44& SkMatrix44::setScale(SkScalar sx, SkScalar sy, SkScalar sz) {
291 this->setIdentity();
292
293 if (1 == sx && 1 == sy && 1 == sz) {
294 return *this;
295 }
296
297 fMat[0][0] = sx;
298 fMat[1][1] = sy;
299 fMat[2][2] = sz;
300 this->setTypeMask(kScale_Mask);
301 return *this;
302}
303
304SkMatrix44& SkMatrix44::preScale(SkScalar sx, SkScalar sy, SkScalar sz) {
305 if (1 == sx && 1 == sy && 1 == sz) {
306 return *this;
307 }
308
309 // The implementation matrix * pureScale can be shortcut
310 // by knowing that pureScale components effectively scale
311 // the columns of the original matrix.
312 for (int i = 0; i < 4; i++) {
313 fMat[0][i] *= sx;
314 fMat[1][i] *= sy;
315 fMat[2][i] *= sz;
316 }
317 this->recomputeTypeMask();
318 return *this;
319}
320
321SkMatrix44& SkMatrix44::postScale(SkScalar sx, SkScalar sy, SkScalar sz) {
322 if (1 == sx && 1 == sy && 1 == sz) {
323 return *this;
324 }
325
326 for (int i = 0; i < 4; i++) {
327 fMat[i][0] *= sx;
328 fMat[i][1] *= sy;
329 fMat[i][2] *= sz;
330 }
331 this->recomputeTypeMask();
332 return *this;
333}
334
335///////////////////////////////////////////////////////////////////////////////
336
337void SkMatrix44::setRotateAbout(SkScalar x, SkScalar y, SkScalar z, SkScalar radians) {
338 double len2 = (double)x * x + (double)y * y + (double)z * z;
339 if (1 != len2) {
340 if (0 == len2) {
341 this->setIdentity();
342 return;
343 }
344 double scale = 1 / sqrt(len2);
345 x = SkScalar(x * scale);
346 y = SkScalar(y * scale);
347 z = SkScalar(z * scale);
348 }
349 this->setRotateAboutUnit(x, y, z, radians);
350}
351
352void SkMatrix44::setRotateAboutUnit(SkScalar x, SkScalar y, SkScalar z, SkScalar radians) {
353 double c = cos(radians);
354 double s = sin(radians);
355 double C = 1 - c;
356 double xs = x * s;
357 double ys = y * s;
358 double zs = z * s;
359 double xC = x * C;
360 double yC = y * C;
361 double zC = z * C;
362 double xyC = x * yC;
363 double yzC = y * zC;
364 double zxC = z * xC;
365
366 // if you're looking at wikipedia, remember that we're column major.
367 this->set3x3(SkScalar(x * xC + c), // scale x
368 SkScalar(xyC + zs), // skew x
369 SkScalar(zxC - ys), // trans x
370
371 SkScalar(xyC - zs), // skew y
372 SkScalar(y * yC + c), // scale y
373 SkScalar(yzC + xs), // trans y
374
375 SkScalar(zxC + ys), // persp x
376 SkScalar(yzC - xs), // persp y
377 SkScalar(z * zC + c)); // persp 2
378}
379
380///////////////////////////////////////////////////////////////////////////////
381
382static bool bits_isonly(int value, int mask) {
383 return 0 == (value & ~mask);
384}
385
386void SkMatrix44::setConcat(const SkMatrix44& a, const SkMatrix44& b) {
387 const SkMatrix44::TypeMask a_mask = a.getType();
388 const SkMatrix44::TypeMask b_mask = b.getType();
389
390 if (kIdentity_Mask == a_mask) {
391 *this = b;
392 return;
393 }
394 if (kIdentity_Mask == b_mask) {
395 *this = a;
396 return;
397 }
398
399 bool useStorage = (this == &a || this == &b);
400 SkScalar storage[16];
401 SkScalar* result = useStorage ? storage : &fMat[0][0];
402
403 // Both matrices are at most scale+translate
404 if (bits_isonly(a_mask | b_mask, kScale_Mask | kTranslate_Mask)) {
405 result[0] = a.fMat[0][0] * b.fMat[0][0];
406 result[1] = result[2] = result[3] = result[4] = 0;
407 result[5] = a.fMat[1][1] * b.fMat[1][1];
408 result[6] = result[7] = result[8] = result[9] = 0;
409 result[10] = a.fMat[2][2] * b.fMat[2][2];
410 result[11] = 0;
411 result[12] = a.fMat[0][0] * b.fMat[3][0] + a.fMat[3][0];
412 result[13] = a.fMat[1][1] * b.fMat[3][1] + a.fMat[3][1];
413 result[14] = a.fMat[2][2] * b.fMat[3][2] + a.fMat[3][2];
414 result[15] = 1;
415 } else {
416 for (int j = 0; j < 4; j++) {
417 for (int i = 0; i < 4; i++) {
418 double value = 0;
419 for (int k = 0; k < 4; k++) {
420 value += double(a.fMat[k][i]) * b.fMat[j][k];
421 }
422 *result++ = SkScalar(value);
423 }
424 }
425 }
426
427 if (useStorage) {
428 memcpy(fMat, storage, sizeof(storage));
429 }
430 this->recomputeTypeMask();
431}
432
433///////////////////////////////////////////////////////////////////////////////
434
435/** We always perform the calculation in doubles, to avoid prematurely losing
436 precision along the way. This relies on the compiler automatically
437 promoting our SkScalar values to double (if needed).
438 */
439double SkMatrix44::determinant() const {
440 if (this->isIdentity()) {
441 return 1;
442 }
443 if (this->isScaleTranslate()) {
444 return fMat[0][0] * fMat[1][1] * fMat[2][2] * fMat[3][3];
445 }
446
447 double a00 = fMat[0][0];
448 double a01 = fMat[0][1];
449 double a02 = fMat[0][2];
450 double a03 = fMat[0][3];
451 double a10 = fMat[1][0];
452 double a11 = fMat[1][1];
453 double a12 = fMat[1][2];
454 double a13 = fMat[1][3];
455 double a20 = fMat[2][0];
456 double a21 = fMat[2][1];
457 double a22 = fMat[2][2];
458 double a23 = fMat[2][3];
459 double a30 = fMat[3][0];
460 double a31 = fMat[3][1];
461 double a32 = fMat[3][2];
462 double a33 = fMat[3][3];
463
464 double b00 = a00 * a11 - a01 * a10;
465 double b01 = a00 * a12 - a02 * a10;
466 double b02 = a00 * a13 - a03 * a10;
467 double b03 = a01 * a12 - a02 * a11;
468 double b04 = a01 * a13 - a03 * a11;
469 double b05 = a02 * a13 - a03 * a12;
470 double b06 = a20 * a31 - a21 * a30;
471 double b07 = a20 * a32 - a22 * a30;
472 double b08 = a20 * a33 - a23 * a30;
473 double b09 = a21 * a32 - a22 * a31;
474 double b10 = a21 * a33 - a23 * a31;
475 double b11 = a22 * a33 - a23 * a32;
476
477 // Calculate the determinant
478 return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
479}
480
481///////////////////////////////////////////////////////////////////////////////
482
483static bool is_matrix_finite(const SkMatrix44& matrix) {
484 SkScalar accumulator = 0;
485 for (int row = 0; row < 4; ++row) {
486 for (int col = 0; col < 4; ++col) {
487 accumulator *= matrix.get(row, col);
488 }
489 }
490 return accumulator == 0;
491}
492
493bool SkMatrix44::invert(SkMatrix44* storage) const {
494 if (this->isIdentity()) {
495 if (storage) {
496 storage->setIdentity();
497 }
498 return true;
499 }
500
501 if (this->isTranslate()) {
502 if (storage) {
503 storage->setTranslate(-fMat[3][0], -fMat[3][1], -fMat[3][2]);
504 }
505 return true;
506 }
507
508 SkMatrix44 tmp;
509 // Use storage if it's available and distinct from this matrix.
510 SkMatrix44* inverse = (storage && storage != this) ? storage : &tmp;
511 if (this->isScaleTranslate()) {
512 if (0 == fMat[0][0] * fMat[1][1] * fMat[2][2]) {
513 return false;
514 }
515
516 double invXScale = 1 / fMat[0][0];
517 double invYScale = 1 / fMat[1][1];
518 double invZScale = 1 / fMat[2][2];
519
520 inverse->fMat[0][0] = SkDoubleToScalar(invXScale);
521 inverse->fMat[0][1] = 0;
522 inverse->fMat[0][2] = 0;
523 inverse->fMat[0][3] = 0;
524
525 inverse->fMat[1][0] = 0;
526 inverse->fMat[1][1] = SkDoubleToScalar(invYScale);
527 inverse->fMat[1][2] = 0;
528 inverse->fMat[1][3] = 0;
529
530 inverse->fMat[2][0] = 0;
531 inverse->fMat[2][1] = 0;
532 inverse->fMat[2][2] = SkDoubleToScalar(invZScale);
533 inverse->fMat[2][3] = 0;
534
535 inverse->fMat[3][0] = SkDoubleToScalar(-fMat[3][0] * invXScale);
536 inverse->fMat[3][1] = SkDoubleToScalar(-fMat[3][1] * invYScale);
537 inverse->fMat[3][2] = SkDoubleToScalar(-fMat[3][2] * invZScale);
538 inverse->fMat[3][3] = 1;
539
540 inverse->setTypeMask(this->getType());
541
542 if (!is_matrix_finite(*inverse)) {
543 return false;
544 }
545 if (storage && inverse != storage) {
546 *storage = *inverse;
547 }
548 return true;
549 }
550
551 double a00 = fMat[0][0];
552 double a01 = fMat[0][1];
553 double a02 = fMat[0][2];
554 double a03 = fMat[0][3];
555 double a10 = fMat[1][0];
556 double a11 = fMat[1][1];
557 double a12 = fMat[1][2];
558 double a13 = fMat[1][3];
559 double a20 = fMat[2][0];
560 double a21 = fMat[2][1];
561 double a22 = fMat[2][2];
562 double a23 = fMat[2][3];
563 double a30 = fMat[3][0];
564 double a31 = fMat[3][1];
565 double a32 = fMat[3][2];
566 double a33 = fMat[3][3];
567
568 if (!(this->getType() & kPerspective_Mask)) {
569 // If we know the matrix has no perspective, then the perspective
570 // component is (0, 0, 0, 1). We can use this information to save a lot
571 // of arithmetic that would otherwise be spent to compute the inverse
572 // of a general matrix.
573
574 SkASSERT(a03 == 0);
575 SkASSERT(a13 == 0);
576 SkASSERT(a23 == 0);
577 SkASSERT(a33 == 1);
578
579 double b00 = a00 * a11 - a01 * a10;
580 double b01 = a00 * a12 - a02 * a10;
581 double b03 = a01 * a12 - a02 * a11;
582 double b06 = a20 * a31 - a21 * a30;
583 double b07 = a20 * a32 - a22 * a30;
584 double b08 = a20;
585 double b09 = a21 * a32 - a22 * a31;
586 double b10 = a21;
587 double b11 = a22;
588
589 // Calculate the determinant
590 double det = b00 * b11 - b01 * b10 + b03 * b08;
591
592 double invdet = sk_ieee_double_divide(1.0, det);
593 // If det is zero, we want to return false. However, we also want to return false
594 // if 1/det overflows to infinity (i.e. det is denormalized). Both of these are
595 // handled by checking that 1/det is finite.
596 if (!sk_float_isfinite(sk_double_to_float(invdet))) {
597 return false;
598 }
599
600 b00 *= invdet;
601 b01 *= invdet;
602 b03 *= invdet;
603 b06 *= invdet;
604 b07 *= invdet;
605 b08 *= invdet;
606 b09 *= invdet;
607 b10 *= invdet;
608 b11 *= invdet;
609
610 inverse->fMat[0][0] = SkDoubleToScalar(a11 * b11 - a12 * b10);
611 inverse->fMat[0][1] = SkDoubleToScalar(a02 * b10 - a01 * b11);
612 inverse->fMat[0][2] = SkDoubleToScalar(b03);
613 inverse->fMat[0][3] = 0;
614 inverse->fMat[1][0] = SkDoubleToScalar(a12 * b08 - a10 * b11);
615 inverse->fMat[1][1] = SkDoubleToScalar(a00 * b11 - a02 * b08);
616 inverse->fMat[1][2] = SkDoubleToScalar(-b01);
617 inverse->fMat[1][3] = 0;
618 inverse->fMat[2][0] = SkDoubleToScalar(a10 * b10 - a11 * b08);
619 inverse->fMat[2][1] = SkDoubleToScalar(a01 * b08 - a00 * b10);
620 inverse->fMat[2][2] = SkDoubleToScalar(b00);
621 inverse->fMat[2][3] = 0;
622 inverse->fMat[3][0] = SkDoubleToScalar(a11 * b07 - a10 * b09 - a12 * b06);
623 inverse->fMat[3][1] = SkDoubleToScalar(a00 * b09 - a01 * b07 + a02 * b06);
624 inverse->fMat[3][2] = SkDoubleToScalar(a31 * b01 - a30 * b03 - a32 * b00);
625 inverse->fMat[3][3] = 1;
626
627 inverse->setTypeMask(this->getType());
628 if (!is_matrix_finite(*inverse)) {
629 return false;
630 }
631 if (storage && inverse != storage) {
632 *storage = *inverse;
633 }
634 return true;
635 }
636
637 double b00 = a00 * a11 - a01 * a10;
638 double b01 = a00 * a12 - a02 * a10;
639 double b02 = a00 * a13 - a03 * a10;
640 double b03 = a01 * a12 - a02 * a11;
641 double b04 = a01 * a13 - a03 * a11;
642 double b05 = a02 * a13 - a03 * a12;
643 double b06 = a20 * a31 - a21 * a30;
644 double b07 = a20 * a32 - a22 * a30;
645 double b08 = a20 * a33 - a23 * a30;
646 double b09 = a21 * a32 - a22 * a31;
647 double b10 = a21 * a33 - a23 * a31;
648 double b11 = a22 * a33 - a23 * a32;
649
650 // Calculate the determinant
651 double det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
652
653 double invdet = sk_ieee_double_divide(1.0, det);
654 // If det is zero, we want to return false. However, we also want to return false
655 // if 1/det overflows to infinity (i.e. det is denormalized). Both of these are
656 // handled by checking that 1/det is finite.
657 if (!sk_float_isfinite(sk_double_to_float(invdet))) {
658 return false;
659 }
660
661 b00 *= invdet;
662 b01 *= invdet;
663 b02 *= invdet;
664 b03 *= invdet;
665 b04 *= invdet;
666 b05 *= invdet;
667 b06 *= invdet;
668 b07 *= invdet;
669 b08 *= invdet;
670 b09 *= invdet;
671 b10 *= invdet;
672 b11 *= invdet;
673
674 inverse->fMat[0][0] = SkDoubleToScalar(a11 * b11 - a12 * b10 + a13 * b09);
675 inverse->fMat[0][1] = SkDoubleToScalar(a02 * b10 - a01 * b11 - a03 * b09);
676 inverse->fMat[0][2] = SkDoubleToScalar(a31 * b05 - a32 * b04 + a33 * b03);
677 inverse->fMat[0][3] = SkDoubleToScalar(a22 * b04 - a21 * b05 - a23 * b03);
678 inverse->fMat[1][0] = SkDoubleToScalar(a12 * b08 - a10 * b11 - a13 * b07);
679 inverse->fMat[1][1] = SkDoubleToScalar(a00 * b11 - a02 * b08 + a03 * b07);
680 inverse->fMat[1][2] = SkDoubleToScalar(a32 * b02 - a30 * b05 - a33 * b01);
681 inverse->fMat[1][3] = SkDoubleToScalar(a20 * b05 - a22 * b02 + a23 * b01);
682 inverse->fMat[2][0] = SkDoubleToScalar(a10 * b10 - a11 * b08 + a13 * b06);
683 inverse->fMat[2][1] = SkDoubleToScalar(a01 * b08 - a00 * b10 - a03 * b06);
684 inverse->fMat[2][2] = SkDoubleToScalar(a30 * b04 - a31 * b02 + a33 * b00);
685 inverse->fMat[2][3] = SkDoubleToScalar(a21 * b02 - a20 * b04 - a23 * b00);
686 inverse->fMat[3][0] = SkDoubleToScalar(a11 * b07 - a10 * b09 - a12 * b06);
687 inverse->fMat[3][1] = SkDoubleToScalar(a00 * b09 - a01 * b07 + a02 * b06);
688 inverse->fMat[3][2] = SkDoubleToScalar(a31 * b01 - a30 * b03 - a32 * b00);
689 inverse->fMat[3][3] = SkDoubleToScalar(a20 * b03 - a21 * b01 + a22 * b00);
690 inverse->setTypeMask(this->getType());
691 if (!is_matrix_finite(*inverse)) {
692 return false;
693 }
694 if (storage && inverse != storage) {
695 *storage = *inverse;
696 }
697 return true;
698}
699
700///////////////////////////////////////////////////////////////////////////////
701
702void SkMatrix44::transpose() {
703 if (!this->isIdentity()) {
704 using std::swap;
705 swap(fMat[0][1], fMat[1][0]);
706 swap(fMat[0][2], fMat[2][0]);
707 swap(fMat[0][3], fMat[3][0]);
708 swap(fMat[1][2], fMat[2][1]);
709 swap(fMat[1][3], fMat[3][1]);
710 swap(fMat[2][3], fMat[3][2]);
711 this->recomputeTypeMask();
712 }
713}
714
715///////////////////////////////////////////////////////////////////////////////
716
717void SkMatrix44::mapScalars(const SkScalar src[4], SkScalar dst[4]) const {
718 SkScalar storage[4];
719 SkScalar* result = (src == dst) ? storage : dst;
720
721 for (int i = 0; i < 4; i++) {
722 SkScalar value = 0;
723 for (int j = 0; j < 4; j++) {
724 value += fMat[j][i] * src[j];
725 }
726 result[i] = value;
727 }
728
729 if (storage == result) {
730 memcpy(dst, storage, sizeof(storage));
731 }
732}
733
734typedef void (*Map2Procf)(const SkScalar mat[][4], const float src2[], int count, float dst4[]);
735typedef void (*Map2Procd)(const SkScalar mat[][4], const double src2[], int count, double dst4[]);
736
737static void map2_if(const SkScalar mat[][4], const float* SK_RESTRICT src2,
738 int count, float* SK_RESTRICT dst4) {
739 for (int i = 0; i < count; ++i) {
740 dst4[0] = src2[0];
741 dst4[1] = src2[1];
742 dst4[2] = 0;
743 dst4[3] = 1;
744 src2 += 2;
745 dst4 += 4;
746 }
747}
748
749static void map2_id(const SkScalar mat[][4], const double* SK_RESTRICT src2,
750 int count, double* SK_RESTRICT dst4) {
751 for (int i = 0; i < count; ++i) {
752 dst4[0] = src2[0];
753 dst4[1] = src2[1];
754 dst4[2] = 0;
755 dst4[3] = 1;
756 src2 += 2;
757 dst4 += 4;
758 }
759}
760
761static void map2_tf(const SkScalar mat[][4], const float* SK_RESTRICT src2,
762 int count, float* SK_RESTRICT dst4) {
763 const float mat30 = float(mat[3][0]);
764 const float mat31 = float(mat[3][1]);
765 const float mat32 = float(mat[3][2]);
766 for (int n = 0; n < count; ++n) {
767 dst4[0] = src2[0] + mat30;
768 dst4[1] = src2[1] + mat31;
769 dst4[2] = mat32;
770 dst4[3] = 1;
771 src2 += 2;
772 dst4 += 4;
773 }
774}
775
776static void map2_td(const SkScalar mat[][4], const double* SK_RESTRICT src2,
777 int count, double* SK_RESTRICT dst4) {
778 for (int n = 0; n < count; ++n) {
779 dst4[0] = src2[0] + mat[3][0];
780 dst4[1] = src2[1] + mat[3][1];
781 dst4[2] = mat[3][2];
782 dst4[3] = 1;
783 src2 += 2;
784 dst4 += 4;
785 }
786}
787
788static void map2_sf(const SkScalar mat[][4], const float* SK_RESTRICT src2,
789 int count, float* SK_RESTRICT dst4) {
790 const float mat32 = float(mat[3][2]);
791 for (int n = 0; n < count; ++n) {
792 dst4[0] = float(mat[0][0] * src2[0] + mat[3][0]);
793 dst4[1] = float(mat[1][1] * src2[1] + mat[3][1]);
794 dst4[2] = mat32;
795 dst4[3] = 1;
796 src2 += 2;
797 dst4 += 4;
798 }
799}
800
801static void map2_sd(const SkScalar mat[][4], const double* SK_RESTRICT src2,
802 int count, double* SK_RESTRICT dst4) {
803 for (int n = 0; n < count; ++n) {
804 dst4[0] = mat[0][0] * src2[0] + mat[3][0];
805 dst4[1] = mat[1][1] * src2[1] + mat[3][1];
806 dst4[2] = mat[3][2];
807 dst4[3] = 1;
808 src2 += 2;
809 dst4 += 4;
810 }
811}
812
813static void map2_af(const SkScalar mat[][4], const float* SK_RESTRICT src2,
814 int count, float* SK_RESTRICT dst4) {
815 SkScalar r;
816 for (int n = 0; n < count; ++n) {
817 SkScalar sx = src2[0];
818 SkScalar sy = src2[1];
819 r = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
820 dst4[0] = float(r);
821 r = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
822 dst4[1] = float(r);
823 r = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
824 dst4[2] = float(r);
825 dst4[3] = 1;
826 src2 += 2;
827 dst4 += 4;
828 }
829}
830
831static void map2_ad(const SkScalar mat[][4], const double* SK_RESTRICT src2,
832 int count, double* SK_RESTRICT dst4) {
833 for (int n = 0; n < count; ++n) {
834 double sx = src2[0];
835 double sy = src2[1];
836 dst4[0] = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
837 dst4[1] = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
838 dst4[2] = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
839 dst4[3] = 1;
840 src2 += 2;
841 dst4 += 4;
842 }
843}
844
845static void map2_pf(const SkScalar mat[][4], const float* SK_RESTRICT src2,
846 int count, float* SK_RESTRICT dst4) {
847 SkScalar r;
848 for (int n = 0; n < count; ++n) {
849 SkScalar sx = src2[0];
850 SkScalar sy = src2[1];
851 for (int i = 0; i < 4; i++) {
852 r = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
853 dst4[i] = float(r);
854 }
855 src2 += 2;
856 dst4 += 4;
857 }
858}
859
860static void map2_pd(const SkScalar mat[][4], const double* SK_RESTRICT src2,
861 int count, double* SK_RESTRICT dst4) {
862 for (int n = 0; n < count; ++n) {
863 double sx = src2[0];
864 double sy = src2[1];
865 for (int i = 0; i < 4; i++) {
866 dst4[i] = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
867 }
868 src2 += 2;
869 dst4 += 4;
870 }
871}
872
873void SkMatrix44::map2(const float src2[], int count, float dst4[]) const {
874 static const Map2Procf gProc[] = {
875 map2_if, map2_tf, map2_sf, map2_sf, map2_af, map2_af, map2_af, map2_af
876 };
877
878 TypeMask mask = this->getType();
879 Map2Procf proc = (mask & kPerspective_Mask) ? map2_pf : gProc[mask];
880 proc(fMat, src2, count, dst4);
881}
882
883void SkMatrix44::map2(const double src2[], int count, double dst4[]) const {
884 static const Map2Procd gProc[] = {
885 map2_id, map2_td, map2_sd, map2_sd, map2_ad, map2_ad, map2_ad, map2_ad
886 };
887
888 TypeMask mask = this->getType();
889 Map2Procd proc = (mask & kPerspective_Mask) ? map2_pd : gProc[mask];
890 proc(fMat, src2, count, dst4);
891}
892
893bool SkMatrix44::preserves2dAxisAlignment (SkScalar epsilon) const {
894
895 // Can't check (mask & kPerspective_Mask) because Z isn't relevant here.
896 if (0 != perspX() || 0 != perspY()) return false;
897
898 // A matrix with two non-zeroish values in any of the upper right
899 // rows or columns will skew. If only one value in each row or
900 // column is non-zeroish, we get a scale plus perhaps a 90-degree
901 // rotation.
902 int col0 = 0;
903 int col1 = 0;
904 int row0 = 0;
905 int row1 = 0;
906
907 // Must test against epsilon, not 0, because we can get values
908 // around 6e-17 in the matrix that "should" be 0.
909
910 if (SkScalarAbs(fMat[0][0]) > epsilon) {
911 col0++;
912 row0++;
913 }
914 if (SkScalarAbs(fMat[0][1]) > epsilon) {
915 col1++;
916 row0++;
917 }
918 if (SkScalarAbs(fMat[1][0]) > epsilon) {
919 col0++;
920 row1++;
921 }
922 if (SkScalarAbs(fMat[1][1]) > epsilon) {
923 col1++;
924 row1++;
925 }
926 if (col0 > 1 || col1 > 1 || row0 > 1 || row1 > 1) {
927 return false;
928 }
929
930 return true;
931}
932
933///////////////////////////////////////////////////////////////////////////////
934
935void SkMatrix44::dump() const {
936 static const char* format = "|%g %g %g %g|\n"
937 "|%g %g %g %g|\n"
938 "|%g %g %g %g|\n"
939 "|%g %g %g %g|\n";
940 SkDebugf(format,
941 fMat[0][0], fMat[1][0], fMat[2][0], fMat[3][0],
942 fMat[0][1], fMat[1][1], fMat[2][1], fMat[3][1],
943 fMat[0][2], fMat[1][2], fMat[2][2], fMat[3][2],
944 fMat[0][3], fMat[1][3], fMat[2][3], fMat[3][3]);
945}
946
947///////////////////////////////////////////////////////////////////////////////
948
949static void initFromMatrix(SkScalar dst[4][4], const SkMatrix& src) {
950 dst[0][0] = src[SkMatrix::kMScaleX];
951 dst[1][0] = src[SkMatrix::kMSkewX];
952 dst[2][0] = 0;
953 dst[3][0] = src[SkMatrix::kMTransX];
954 dst[0][1] = src[SkMatrix::kMSkewY];
955 dst[1][1] = src[SkMatrix::kMScaleY];
956 dst[2][1] = 0;
957 dst[3][1] = src[SkMatrix::kMTransY];
958 dst[0][2] = 0;
959 dst[1][2] = 0;
960 dst[2][2] = 1;
961 dst[3][2] = 0;
962 dst[0][3] = src[SkMatrix::kMPersp0];
963 dst[1][3] = src[SkMatrix::kMPersp1];
964 dst[2][3] = 0;
965 dst[3][3] = src[SkMatrix::kMPersp2];
966}
967
968SkMatrix44::SkMatrix44(const SkMatrix& src) {
969 this->operator=(src);
970}
971
972SkMatrix44& SkMatrix44::operator=(const SkMatrix& src) {
973 initFromMatrix(fMat, src);
974
975 if (src.isIdentity()) {
976 this->setTypeMask(kIdentity_Mask);
977 } else {
978 this->recomputeTypeMask();
979 }
980 return *this;
981}
982
983SkMatrix44::operator SkMatrix() const {
984 SkMatrix dst;
985
986 dst[SkMatrix::kMScaleX] = fMat[0][0];
987 dst[SkMatrix::kMSkewX] = fMat[1][0];
988 dst[SkMatrix::kMTransX] = fMat[3][0];
989
990 dst[SkMatrix::kMSkewY] = fMat[0][1];
991 dst[SkMatrix::kMScaleY] = fMat[1][1];
992 dst[SkMatrix::kMTransY] = fMat[3][1];
993
994 dst[SkMatrix::kMPersp0] = fMat[0][3];
995 dst[SkMatrix::kMPersp1] = fMat[1][3];
996 dst[SkMatrix::kMPersp2] = fMat[3][3];
997
998 return dst;
999}
1000