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