blob: 1e48f393ac6fd372faf781cd86af63122eb90466 [file] [log] [blame]
reed@google.com8260a892011-06-13 14:02:52 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * 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.
reed@google.com8260a892011-06-13 14:02:52 +00006 */
7
reed@google.com8260a892011-06-13 14:02:52 +00008#include "SkMatrix44.h"
9
reed@google.com7d683352012-12-03 21:19:52 +000010static 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}
jamesr@chromium.orgdeb4c162012-11-29 21:17:16 +000014
reed@google.com7d683352012-12-03 21:19:52 +000015bool 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
reed@google.com631940c2012-11-27 13:13:22 +000028 for (int i = 0; i < 16; ++i) {
29 if (a[i] != b[i]) {
30 return false;
31 }
32 }
33 return true;
reed@google.com7d683352012-12-03 21:19:52 +000034#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;
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +000054
reed@google.com7d683352012-12-03 21:19:52 +000055 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;
reed@google.com8260a892011-06-13 14:02:52 +000073}
74
75///////////////////////////////////////////////////////////////////////////////
76
reed@google.comda9fac02011-06-13 14:46:52 +000077void 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 }
vollick@chromium.org5596a692012-11-13 20:12:00 +000083#elif defined SK_MSCALAR_IS_FLOAT
reed@google.comda9fac02011-06-13 14:46:52 +000084 memcpy(dst, src, 16 * sizeof(float));
85#endif
86}
87
88void SkMatrix44::asColMajord(double dst[]) const {
89 const SkMScalar* src = &fMat[0][0];
90#ifdef SK_MSCALAR_IS_DOUBLE
91 memcpy(dst, src, 16 * sizeof(double));
vollick@chromium.org5596a692012-11-13 20:12:00 +000092#elif defined SK_MSCALAR_IS_FLOAT
reed@google.comda9fac02011-06-13 14:46:52 +000093 for (int i = 0; i < 16; ++i) {
94 dst[i] = SkMScalarToDouble(src[i]);
95 }
96#endif
97}
98
99void SkMatrix44::asRowMajorf(float dst[]) const {
100 const SkMScalar* src = &fMat[0][0];
101 for (int i = 0; i < 4; ++i) {
102 dst[0] = SkMScalarToFloat(src[0]);
103 dst[4] = SkMScalarToFloat(src[1]);
104 dst[8] = SkMScalarToFloat(src[2]);
105 dst[12] = SkMScalarToFloat(src[3]);
106 src += 4;
107 dst += 1;
108 }
109}
110
111void SkMatrix44::asRowMajord(double dst[]) const {
112 const SkMScalar* src = &fMat[0][0];
113 for (int i = 0; i < 4; ++i) {
114 dst[0] = SkMScalarToDouble(src[0]);
115 dst[4] = SkMScalarToDouble(src[1]);
116 dst[8] = SkMScalarToDouble(src[2]);
117 dst[12] = SkMScalarToDouble(src[3]);
118 src += 4;
119 dst += 1;
120 }
121}
122
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000123void SkMatrix44::setColMajorf(const float src[]) {
124 SkMScalar* dst = &fMat[0][0];
125#ifdef SK_MSCALAR_IS_DOUBLE
126 for (int i = 0; i < 16; ++i) {
127 dst[i] = SkMScalarToFloat(src[i]);
128 }
129#elif defined SK_MSCALAR_IS_FLOAT
130 memcpy(dst, src, 16 * sizeof(float));
131#endif
reed@google.com7d683352012-12-03 21:19:52 +0000132
133 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000134}
135
136void SkMatrix44::setColMajord(const double src[]) {
137 SkMScalar* dst = &fMat[0][0];
138#ifdef SK_MSCALAR_IS_DOUBLE
139 memcpy(dst, src, 16 * sizeof(double));
140#elif defined SK_MSCALAR_IS_FLOAT
141 for (int i = 0; i < 16; ++i) {
robertphillips@google.com93f03322012-12-03 17:35:19 +0000142 dst[i] = SkDoubleToMScalar(src[i]);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000143 }
144#endif
reed@google.com7d683352012-12-03 21:19:52 +0000145
146 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000147}
148
149void SkMatrix44::setRowMajorf(const float src[]) {
150 SkMScalar* dst = &fMat[0][0];
151 for (int i = 0; i < 4; ++i) {
152 dst[0] = SkMScalarToFloat(src[0]);
153 dst[4] = SkMScalarToFloat(src[1]);
154 dst[8] = SkMScalarToFloat(src[2]);
155 dst[12] = SkMScalarToFloat(src[3]);
156 src += 4;
157 dst += 1;
158 }
reed@google.com7d683352012-12-03 21:19:52 +0000159 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000160}
161
162void SkMatrix44::setRowMajord(const double src[]) {
163 SkMScalar* dst = &fMat[0][0];
164 for (int i = 0; i < 4; ++i) {
robertphillips@google.com93f03322012-12-03 17:35:19 +0000165 dst[0] = SkDoubleToMScalar(src[0]);
166 dst[4] = SkDoubleToMScalar(src[1]);
167 dst[8] = SkDoubleToMScalar(src[2]);
168 dst[12] = SkDoubleToMScalar(src[3]);
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000169 src += 4;
170 dst += 1;
171 }
reed@google.com7d683352012-12-03 21:19:52 +0000172 this->dirtyTypeMask();
vollick@chromium.orgf11cf9f2012-11-19 21:02:06 +0000173}
174
reed@google.comda9fac02011-06-13 14:46:52 +0000175///////////////////////////////////////////////////////////////////////////////
176
reed@google.com7d683352012-12-03 21:19:52 +0000177const SkMatrix44& SkMatrix44::I() {
reed@google.com1adad342012-12-10 21:21:27 +0000178 static const SkMatrix44 gIdentity44(kIdentity_Constructor);
179 return gIdentity44;
reed@google.com8260a892011-06-13 14:02:52 +0000180}
181
reed@google.com8260a892011-06-13 14:02:52 +0000182void SkMatrix44::setIdentity() {
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000183 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;
reed@google.com7d683352012-12-03 21:19:52 +0000199 this->setTypeMask(kIdentity_Mask);
reed@google.com8260a892011-06-13 14:02:52 +0000200}
201
202void SkMatrix44::set3x3(SkMScalar m00, SkMScalar m01, SkMScalar m02,
203 SkMScalar m10, SkMScalar m11, SkMScalar m12,
204 SkMScalar m20, SkMScalar m21, SkMScalar m22) {
reed@google.com8260a892011-06-13 14:02:52 +0000205 fMat[0][0] = m00; fMat[0][1] = m01; fMat[0][2] = m02; fMat[0][3] = 0;
206 fMat[1][0] = m10; fMat[1][1] = m11; fMat[1][2] = m12; fMat[1][3] = 0;
207 fMat[2][0] = m20; fMat[2][1] = m21; fMat[2][2] = m22; fMat[2][3] = 0;
208 fMat[3][0] = 0; fMat[3][1] = 0; fMat[3][2] = 0; fMat[3][3] = 1;
reed@google.com7d683352012-12-03 21:19:52 +0000209 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000210}
211
212///////////////////////////////////////////////////////////////////////////////
213
reed@google.com99b5c7f2012-12-05 22:13:59 +0000214void SkMatrix44::setTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
reed@google.com8260a892011-06-13 14:02:52 +0000215 this->setIdentity();
skia.committer@gmail.come659c2e2012-12-04 02:01:25 +0000216
reed@google.com99b5c7f2012-12-05 22:13:59 +0000217 if (!dx && !dy && !dz) {
218 return;
reed@google.com7d683352012-12-03 21:19:52 +0000219 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000220
reed@google.com99b5c7f2012-12-05 22:13:59 +0000221 fMat[3][0] = dx;
222 fMat[3][1] = dy;
223 fMat[3][2] = dz;
224 this->setTypeMask(kTranslate_Mask);
reed@google.com8260a892011-06-13 14:02:52 +0000225}
226
227void SkMatrix44::preTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000228 if (!dx && !dy && !dz) {
229 return;
230 }
231
232 const double X = SkMScalarToDouble(dx);
233 const double Y = SkMScalarToDouble(dy);
234 const double Z = SkMScalarToDouble(dz);
235
236 double tmp;
237 for (int i = 0; i < 4; ++i) {
238 tmp = fMat[0][i] * X + fMat[1][i] * Y + fMat[2][i] * Z + fMat[3][i];
239 fMat[3][i] = SkDoubleToMScalar(tmp);
240 }
241 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000242}
243
244void SkMatrix44::postTranslate(SkMScalar dx, SkMScalar dy, SkMScalar dz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000245 if (!dx && !dy && !dz) {
246 return;
247 }
248
249 if (this->getType() & kPerspective_Mask) {
250 for (int i = 0; i < 4; ++i) {
251 fMat[i][0] += fMat[i][3] * dx;
252 fMat[i][1] += fMat[i][3] * dy;
253 fMat[i][2] += fMat[i][3] * dz;
254 }
255 } else {
256 fMat[3][0] += dx;
257 fMat[3][1] += dy;
258 fMat[3][2] += dz;
259 this->dirtyTypeMask();
260 }
reed@google.com8260a892011-06-13 14:02:52 +0000261}
262
263///////////////////////////////////////////////////////////////////////////////
264
265void SkMatrix44::setScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000266 this->setIdentity();
267
268 if (1 == sx && 1 == sy && 1 == sz) {
269 return;
270 }
271
reed@google.com8260a892011-06-13 14:02:52 +0000272 fMat[0][0] = sx;
273 fMat[1][1] = sy;
274 fMat[2][2] = sz;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000275 this->setTypeMask(kScale_Mask);
reed@google.com8260a892011-06-13 14:02:52 +0000276}
277
278void SkMatrix44::preScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000279 if (1 == sx && 1 == sy && 1 == sz) {
280 return;
281 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000282
shawnsingh@chromium.orgf81f97e2012-12-13 22:21:36 +0000283 // The implementation matrix * pureScale can be shortcut
284 // by knowing that pureScale components effectively scale
285 // the columns of the original matrix.
286 for (int i = 0; i < 4; i++) {
287 fMat[0][i] *= sx;
288 fMat[1][i] *= sy;
289 fMat[2][i] *= sz;
290 }
291 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000292}
293
294void SkMatrix44::postScale(SkMScalar sx, SkMScalar sy, SkMScalar sz) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000295 if (1 == sx && 1 == sy && 1 == sz) {
296 return;
297 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000298
reed@google.com8260a892011-06-13 14:02:52 +0000299 for (int i = 0; i < 4; i++) {
300 fMat[i][0] *= sx;
301 fMat[i][1] *= sy;
302 fMat[i][2] *= sz;
303 }
reed@google.com7d683352012-12-03 21:19:52 +0000304 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000305}
306
307///////////////////////////////////////////////////////////////////////////////
308
309void SkMatrix44::setRotateAbout(SkMScalar x, SkMScalar y, SkMScalar z,
310 SkMScalar radians) {
reed@google.com7d683352012-12-03 21:19:52 +0000311 double len2 = (double)x * x + (double)y * y + (double)z * z;
312 if (1 != len2) {
313 if (0 == len2) {
reed@google.com8260a892011-06-13 14:02:52 +0000314 this->setIdentity();
315 return;
316 }
317 double scale = 1 / sqrt(len2);
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000318 x = SkDoubleToMScalar(x * scale);
319 y = SkDoubleToMScalar(y * scale);
320 z = SkDoubleToMScalar(z * scale);
reed@google.com8260a892011-06-13 14:02:52 +0000321 }
322 this->setRotateAboutUnit(x, y, z, radians);
323}
324
325void SkMatrix44::setRotateAboutUnit(SkMScalar x, SkMScalar y, SkMScalar z,
326 SkMScalar radians) {
327 double c = cos(radians);
328 double s = sin(radians);
329 double C = 1 - c;
330 double xs = x * s;
331 double ys = y * s;
332 double zs = z * s;
333 double xC = x * C;
334 double yC = y * C;
335 double zC = z * C;
336 double xyC = x * yC;
337 double yzC = y * zC;
338 double zxC = z * xC;
339
340 // if you're looking at wikipedia, remember that we're column major.
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000341 this->set3x3(SkDoubleToMScalar(x * xC + c), // scale x
342 SkDoubleToMScalar(xyC + zs), // skew x
343 SkDoubleToMScalar(zxC - ys), // trans x
344
345 SkDoubleToMScalar(xyC - zs), // skew y
346 SkDoubleToMScalar(y * yC + c), // scale y
347 SkDoubleToMScalar(yzC + xs), // trans y
348
349 SkDoubleToMScalar(zxC + ys), // persp x
350 SkDoubleToMScalar(yzC - xs), // persp y
351 SkDoubleToMScalar(z * zC + c)); // persp 2
reed@google.com8260a892011-06-13 14:02:52 +0000352}
353
354///////////////////////////////////////////////////////////////////////////////
355
reed@google.com99b5c7f2012-12-05 22:13:59 +0000356static bool bits_isonly(int value, int mask) {
357 return 0 == (value & ~mask);
358}
359
reed@google.com8260a892011-06-13 14:02:52 +0000360void SkMatrix44::setConcat(const SkMatrix44& a, const SkMatrix44& b) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000361 const SkMatrix44::TypeMask a_mask = a.getType();
362 const SkMatrix44::TypeMask b_mask = b.getType();
363
364 if (kIdentity_Mask == a_mask) {
reed@google.com7d683352012-12-03 21:19:52 +0000365 *this = b;
366 return;
367 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000368 if (kIdentity_Mask == b_mask) {
reed@google.com7d683352012-12-03 21:19:52 +0000369 *this = a;
370 return;
371 }
372
373 bool useStorage = (this == &a || this == &b);
374 SkMScalar storage[16];
375 SkMScalar* result = useStorage ? storage : &fMat[0][0];
376
reed@google.com2b165702013-01-17 16:01:19 +0000377 // Both matrices are at most scale+translate
reed@google.com99b5c7f2012-12-05 22:13:59 +0000378 if (bits_isonly(a_mask | b_mask, kScale_Mask | kTranslate_Mask)) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000379 result[0] = a.fMat[0][0] * b.fMat[0][0];
reed@google.com2b165702013-01-17 16:01:19 +0000380 result[1] = result[2] = result[3] = result[4] = 0;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000381 result[5] = a.fMat[1][1] * b.fMat[1][1];
reed@google.com2b165702013-01-17 16:01:19 +0000382 result[6] = result[7] = result[8] = result[9] = 0;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000383 result[10] = a.fMat[2][2] * b.fMat[2][2];
reed@google.com2b165702013-01-17 16:01:19 +0000384 result[11] = 0;
reed@google.com99b5c7f2012-12-05 22:13:59 +0000385 result[12] = a.fMat[0][0] * b.fMat[3][0] + a.fMat[3][0];
386 result[13] = a.fMat[1][1] * b.fMat[3][1] + a.fMat[3][1];
387 result[14] = a.fMat[2][2] * b.fMat[3][2] + a.fMat[3][2];
388 result[15] = 1;
389 } else {
390 for (int j = 0; j < 4; j++) {
391 for (int i = 0; i < 4; i++) {
392 double value = 0;
393 for (int k = 0; k < 4; k++) {
394 value += SkMScalarToDouble(a.fMat[k][i]) * b.fMat[j][k];
395 }
396 *result++ = SkDoubleToMScalar(value);
reed@google.com8260a892011-06-13 14:02:52 +0000397 }
reed@google.com8260a892011-06-13 14:02:52 +0000398 }
399 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000400
reed@google.com7d683352012-12-03 21:19:52 +0000401 if (useStorage) {
tomhudson@google.com7cfb9c72013-01-17 13:29:35 +0000402 memcpy(fMat, storage, sizeof(storage));
reed@google.com7d683352012-12-03 21:19:52 +0000403 }
reed@google.com7d683352012-12-03 21:19:52 +0000404 this->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000405}
406
407///////////////////////////////////////////////////////////////////////////////
408
409static inline SkMScalar det2x2(double m00, double m01, double m10, double m11) {
bsalomon@google.com9d12f5c2011-09-29 18:08:18 +0000410 return SkDoubleToMScalar(m00 * m11 - m10 * m01);
reed@google.com8260a892011-06-13 14:02:52 +0000411}
412
413static inline double det3x3(double m00, double m01, double m02,
414 double m10, double m11, double m12,
415 double m20, double m21, double m22) {
416 return m00 * det2x2(m11, m12, m21, m22) -
417 m10 * det2x2(m01, m02, m21, m22) +
418 m20 * det2x2(m01, m02, m11, m12);
419}
420
421/** We always perform the calculation in doubles, to avoid prematurely losing
422 precision along the way. This relies on the compiler automatically
423 promoting our SkMScalar values to double (if needed).
424 */
425double SkMatrix44::determinant() const {
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000426 if (this->isIdentity()) {
427 return 1;
428 }
429 if (this->isScaleTranslate()) {
430 return fMat[0][0] * fMat[1][1] * fMat[2][2] * fMat[3][3];
431 }
432
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000433 double a00 = fMat[0][0];
434 double a01 = fMat[0][1];
435 double a02 = fMat[0][2];
436 double a03 = fMat[0][3];
437 double a10 = fMat[1][0];
438 double a11 = fMat[1][1];
439 double a12 = fMat[1][2];
440 double a13 = fMat[1][3];
441 double a20 = fMat[2][0];
442 double a21 = fMat[2][1];
443 double a22 = fMat[2][2];
444 double a23 = fMat[2][3];
445 double a30 = fMat[3][0];
446 double a31 = fMat[3][1];
447 double a32 = fMat[3][2];
448 double a33 = fMat[3][3];
449
450 double b00 = a00 * a11 - a01 * a10;
451 double b01 = a00 * a12 - a02 * a10;
452 double b02 = a00 * a13 - a03 * a10;
453 double b03 = a01 * a12 - a02 * a11;
454 double b04 = a01 * a13 - a03 * a11;
455 double b05 = a02 * a13 - a03 * a12;
456 double b06 = a20 * a31 - a21 * a30;
457 double b07 = a20 * a32 - a22 * a30;
458 double b08 = a20 * a33 - a23 * a30;
459 double b09 = a21 * a32 - a22 * a31;
460 double b10 = a21 * a33 - a23 * a31;
461 double b11 = a22 * a33 - a23 * a32;
462
463 // Calculate the determinant
464 return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
reed@google.com8260a892011-06-13 14:02:52 +0000465}
466
467///////////////////////////////////////////////////////////////////////////////
468
reed@google.com8260a892011-06-13 14:02:52 +0000469static inline double dabs(double x) {
470 if (x < 0) {
471 x = -x;
472 }
473 return x;
474}
475
476bool SkMatrix44::invert(SkMatrix44* inverse) const {
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000477 if (this->isIdentity()) {
reed@google.com7d683352012-12-03 21:19:52 +0000478 if (inverse) {
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000479 inverse->setIdentity();
reed@google.com7d683352012-12-03 21:19:52 +0000480 return true;
481 }
482 }
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000483 if (this->isTranslate()) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000484 if (inverse) {
485 inverse->setTranslate(-fMat[3][0], -fMat[3][1], -fMat[3][2]);
486 }
487 return true;
488 }
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000489 if (this->isScaleTranslate()) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000490 if (0 == fMat[0][0] * fMat[1][1] * fMat[2][2]) {
491 return false;
492 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000493
skia.committer@gmail.com772c4e62013-08-30 07:01:34 +0000494 if (inverse) {
495 double invXScale = 1 / fMat[0][0];
496 double invYScale = 1 / fMat[1][1];
497 double invZScale = 1 / fMat[2][2];
reed@google.com99b5c7f2012-12-05 22:13:59 +0000498
skia.committer@gmail.com772c4e62013-08-30 07:01:34 +0000499 inverse->fMat[0][0] = invXScale;
500 inverse->fMat[0][1] = 0;
501 inverse->fMat[0][2] = 0;
502 inverse->fMat[0][3] = 0;
503
504 inverse->fMat[1][0] = 0;
505 inverse->fMat[1][1] = invYScale;
506 inverse->fMat[1][2] = 0;
507 inverse->fMat[1][3] = 0;
508
509 inverse->fMat[2][0] = 0;
commit-bot@chromium.orgc33d6212013-08-29 15:34:50 +0000510 inverse->fMat[2][1] = 0;
skia.committer@gmail.com772c4e62013-08-30 07:01:34 +0000511 inverse->fMat[2][2] = invZScale;
512 inverse->fMat[2][3] = 0;
513
commit-bot@chromium.orgc33d6212013-08-29 15:34:50 +0000514 inverse->fMat[3][0] = -fMat[3][0] * invXScale;
515 inverse->fMat[3][1] = -fMat[3][1] * invYScale;
516 inverse->fMat[3][2] = -fMat[3][2] * invZScale;
517 inverse->fMat[3][3] = 1;
shawnsingh@chromium.orgb6823c12013-08-22 20:24:21 +0000518
commit-bot@chromium.orgc33d6212013-08-29 15:34:50 +0000519 inverse->setTypeMask(this->getType());
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000520 }
521
reed@google.com99b5c7f2012-12-05 22:13:59 +0000522 return true;
523 }
524
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000525 double a00 = fMat[0][0];
526 double a01 = fMat[0][1];
527 double a02 = fMat[0][2];
528 double a03 = fMat[0][3];
529 double a10 = fMat[1][0];
530 double a11 = fMat[1][1];
531 double a12 = fMat[1][2];
532 double a13 = fMat[1][3];
533 double a20 = fMat[2][0];
534 double a21 = fMat[2][1];
535 double a22 = fMat[2][2];
536 double a23 = fMat[2][3];
537 double a30 = fMat[3][0];
538 double a31 = fMat[3][1];
539 double a32 = fMat[3][2];
540 double a33 = fMat[3][3];
541
shawnsingh@chromium.orgb6823c12013-08-22 20:24:21 +0000542 if (!(this->getType() & kPerspective_Mask)) {
543 // If we know the matrix has no perspective, then the perspective
544 // component is (0, 0, 0, 1). We can use this information to save a lot
545 // of arithmetic that would otherwise be spent to compute the inverse
546 // of a general matrix.
547
548 SkASSERT(a03 == 0);
549 SkASSERT(a13 == 0);
550 SkASSERT(a23 == 0);
551 SkASSERT(a33 == 1);
552
553 double b00 = a00 * a11 - a01 * a10;
554 double b01 = a00 * a12 - a02 * a10;
555 double b03 = a01 * a12 - a02 * a11;
556 double b06 = a20 * a31 - a21 * a30;
557 double b07 = a20 * a32 - a22 * a30;
558 double b08 = a20;
559 double b09 = a21 * a32 - a22 * a31;
560 double b10 = a21;
561 double b11 = a22;
562
563 // Calculate the determinant
564 double det = b00 * b11 - b01 * b10 + b03 * b08;
565
566 double invdet = 1.0 / det;
567 // If det is zero, we want to return false. However, we also want to return false
568 // if 1/det overflows to infinity (i.e. det is denormalized). Both of these are
569 // handled by checking that 1/det is finite.
570 if (!sk_float_isfinite(invdet)) {
571 return false;
572 }
573 if (NULL == inverse) {
574 return true;
575 }
576
577 b00 *= invdet;
578 b01 *= invdet;
579 b03 *= invdet;
580 b06 *= invdet;
581 b07 *= invdet;
582 b08 *= invdet;
583 b09 *= invdet;
584 b10 *= invdet;
585 b11 *= invdet;
586
587 inverse->fMat[0][0] = SkDoubleToMScalar(a11 * b11 - a12 * b10);
588 inverse->fMat[0][1] = SkDoubleToMScalar(a02 * b10 - a01 * b11);
589 inverse->fMat[0][2] = SkDoubleToMScalar(b03);
590 inverse->fMat[0][3] = 0;
591 inverse->fMat[1][0] = SkDoubleToMScalar(a12 * b08 - a10 * b11);
592 inverse->fMat[1][1] = SkDoubleToMScalar(a00 * b11 - a02 * b08);
593 inverse->fMat[1][2] = SkDoubleToMScalar(-b01);
594 inverse->fMat[1][3] = 0;
595 inverse->fMat[2][0] = SkDoubleToMScalar(a10 * b10 - a11 * b08);
596 inverse->fMat[2][1] = SkDoubleToMScalar(a01 * b08 - a00 * b10);
597 inverse->fMat[2][2] = SkDoubleToMScalar(b00);
598 inverse->fMat[2][3] = 0;
599 inverse->fMat[3][0] = SkDoubleToMScalar(a11 * b07 - a10 * b09 - a12 * b06);
600 inverse->fMat[3][1] = SkDoubleToMScalar(a00 * b09 - a01 * b07 + a02 * b06);
601 inverse->fMat[3][2] = SkDoubleToMScalar(a31 * b01 - a30 * b03 - a32 * b00);
602 inverse->fMat[3][3] = 1;
603
604 inverse->setTypeMask(this->getType());
605 return true;
606 }
607
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000608 double b00 = a00 * a11 - a01 * a10;
609 double b01 = a00 * a12 - a02 * a10;
610 double b02 = a00 * a13 - a03 * a10;
611 double b03 = a01 * a12 - a02 * a11;
612 double b04 = a01 * a13 - a03 * a11;
613 double b05 = a02 * a13 - a03 * a12;
614 double b06 = a20 * a31 - a21 * a30;
615 double b07 = a20 * a32 - a22 * a30;
616 double b08 = a20 * a33 - a23 * a30;
617 double b09 = a21 * a32 - a22 * a31;
618 double b10 = a21 * a33 - a23 * a31;
619 double b11 = a22 * a33 - a23 * a32;
620
621 // Calculate the determinant
622 double det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
623
commit-bot@chromium.orgf02f0782013-08-20 15:25:04 +0000624 double invdet = 1.0 / det;
625 // If det is zero, we want to return false. However, we also want to return false
626 // if 1/det overflows to infinity (i.e. det is denormalized). Both of these are
627 // handled by checking that 1/det is finite.
628 if (!sk_float_isfinite(invdet)) {
reed@google.com8260a892011-06-13 14:02:52 +0000629 return false;
630 }
631 if (NULL == inverse) {
632 return true;
633 }
634
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000635 b00 *= invdet;
636 b01 *= invdet;
637 b02 *= invdet;
638 b03 *= invdet;
639 b04 *= invdet;
640 b05 *= invdet;
641 b06 *= invdet;
642 b07 *= invdet;
643 b08 *= invdet;
644 b09 *= invdet;
645 b10 *= invdet;
646 b11 *= invdet;
reed@google.com8260a892011-06-13 14:02:52 +0000647
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000648 inverse->fMat[0][0] = SkDoubleToMScalar(a11 * b11 - a12 * b10 + a13 * b09);
649 inverse->fMat[0][1] = SkDoubleToMScalar(a02 * b10 - a01 * b11 - a03 * b09);
650 inverse->fMat[0][2] = SkDoubleToMScalar(a31 * b05 - a32 * b04 + a33 * b03);
651 inverse->fMat[0][3] = SkDoubleToMScalar(a22 * b04 - a21 * b05 - a23 * b03);
652 inverse->fMat[1][0] = SkDoubleToMScalar(a12 * b08 - a10 * b11 - a13 * b07);
653 inverse->fMat[1][1] = SkDoubleToMScalar(a00 * b11 - a02 * b08 + a03 * b07);
654 inverse->fMat[1][2] = SkDoubleToMScalar(a32 * b02 - a30 * b05 - a33 * b01);
655 inverse->fMat[1][3] = SkDoubleToMScalar(a20 * b05 - a22 * b02 + a23 * b01);
656 inverse->fMat[2][0] = SkDoubleToMScalar(a10 * b10 - a11 * b08 + a13 * b06);
657 inverse->fMat[2][1] = SkDoubleToMScalar(a01 * b08 - a00 * b10 - a03 * b06);
658 inverse->fMat[2][2] = SkDoubleToMScalar(a30 * b04 - a31 * b02 + a33 * b00);
659 inverse->fMat[2][3] = SkDoubleToMScalar(a21 * b02 - a20 * b04 - a23 * b00);
660 inverse->fMat[3][0] = SkDoubleToMScalar(a11 * b07 - a10 * b09 - a12 * b06);
661 inverse->fMat[3][1] = SkDoubleToMScalar(a00 * b09 - a01 * b07 + a02 * b06);
662 inverse->fMat[3][2] = SkDoubleToMScalar(a31 * b01 - a30 * b03 - a32 * b00);
663 inverse->fMat[3][3] = SkDoubleToMScalar(a20 * b03 - a21 * b01 + a22 * b00);
664 inverse->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000665
reed@google.com8260a892011-06-13 14:02:52 +0000666 return true;
667}
668
669///////////////////////////////////////////////////////////////////////////////
670
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000671void SkMatrix44::transpose() {
672 SkTSwap(fMat[0][1], fMat[1][0]);
673 SkTSwap(fMat[0][2], fMat[2][0]);
674 SkTSwap(fMat[0][3], fMat[3][0]);
675 SkTSwap(fMat[1][2], fMat[2][1]);
676 SkTSwap(fMat[1][3], fMat[3][1]);
677 SkTSwap(fMat[2][3], fMat[3][2]);
reed@google.com7d683352012-12-03 21:19:52 +0000678
679 if (!this->isTriviallyIdentity()) {
680 this->dirtyTypeMask();
681 }
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000682}
683
684///////////////////////////////////////////////////////////////////////////////
685
reed@google.com1ea95be2012-11-09 21:39:48 +0000686void SkMatrix44::mapScalars(const SkScalar src[4], SkScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000687 SkScalar storage[4];
688 SkScalar* result = (src == dst) ? storage : dst;
689
reed@google.com8260a892011-06-13 14:02:52 +0000690 for (int i = 0; i < 4; i++) {
691 SkMScalar value = 0;
692 for (int j = 0; j < 4; j++) {
693 value += fMat[j][i] * src[j];
694 }
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000695 result[i] = SkMScalarToScalar(value);
reed@google.com8260a892011-06-13 14:02:52 +0000696 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000697
reed@google.com7d683352012-12-03 21:19:52 +0000698 if (storage == result) {
699 memcpy(dst, storage, sizeof(storage));
700 }
reed@google.com8260a892011-06-13 14:02:52 +0000701}
702
reed@google.com1ea95be2012-11-09 21:39:48 +0000703#ifdef SK_MSCALAR_IS_DOUBLE
reed@google.com7d683352012-12-03 21:19:52 +0000704
reed@google.com1ea95be2012-11-09 21:39:48 +0000705void SkMatrix44::mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000706 SkMScalar storage[4];
707 SkMScalar* result = (src == dst) ? storage : dst;
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000708
reed@google.com1ea95be2012-11-09 21:39:48 +0000709 for (int i = 0; i < 4; i++) {
710 SkMScalar value = 0;
711 for (int j = 0; j < 4; j++) {
712 value += fMat[j][i] * src[j];
713 }
reed@google.com7d683352012-12-03 21:19:52 +0000714 result[i] = value;
reed@google.com1ea95be2012-11-09 21:39:48 +0000715 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000716
reed@google.com7d683352012-12-03 21:19:52 +0000717 if (storage == result) {
718 memcpy(dst, storage, sizeof(storage));
719 }
reed@google.com1ea95be2012-11-09 21:39:48 +0000720}
reed@google.com7d683352012-12-03 21:19:52 +0000721
reed@google.com1ea95be2012-11-09 21:39:48 +0000722#endif
723
reed@google.com99b5c7f2012-12-05 22:13:59 +0000724typedef void (*Map2Procf)(const SkMScalar mat[][4], const float src2[], int count, float dst4[]);
725typedef void (*Map2Procd)(const SkMScalar mat[][4], const double src2[], int count, double dst4[]);
726
727static void map2_if(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
728 int count, float* SK_RESTRICT dst4) {
729 for (int i = 0; i < count; ++i) {
730 dst4[0] = src2[0];
731 dst4[1] = src2[1];
732 dst4[2] = 0;
733 dst4[3] = 1;
734 src2 += 2;
735 dst4 += 4;
736 }
737}
738
739static void map2_id(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
740 int count, double* SK_RESTRICT dst4) {
741 for (int i = 0; i < count; ++i) {
742 dst4[0] = src2[0];
743 dst4[1] = src2[1];
744 dst4[2] = 0;
745 dst4[3] = 1;
746 src2 += 2;
747 dst4 += 4;
748 }
749}
750
751static void map2_tf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
752 int count, float* SK_RESTRICT dst4) {
753 const float mat30 = SkMScalarToFloat(mat[3][0]);
754 const float mat31 = SkMScalarToFloat(mat[3][1]);
755 const float mat32 = SkMScalarToFloat(mat[3][2]);
756 for (int n = 0; n < count; ++n) {
757 dst4[0] = src2[0] + mat30;
758 dst4[1] = src2[1] + mat31;
759 dst4[2] = mat32;
760 dst4[3] = 1;
761 src2 += 2;
762 dst4 += 4;
763 }
764}
765
766static void map2_td(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
767 int count, double* SK_RESTRICT dst4) {
768 for (int n = 0; n < count; ++n) {
769 dst4[0] = src2[0] + mat[3][0];
770 dst4[1] = src2[1] + mat[3][1];
771 dst4[2] = mat[3][2];
772 dst4[3] = 1;
773 src2 += 2;
774 dst4 += 4;
775 }
776}
777
778static void map2_sf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
779 int count, float* SK_RESTRICT dst4) {
780 const float mat32 = SkMScalarToFloat(mat[3][2]);
781 for (int n = 0; n < count; ++n) {
782 dst4[0] = SkMScalarToFloat(mat[0][0] * src2[0] + mat[3][0]);
783 dst4[1] = SkMScalarToFloat(mat[1][1] * src2[1] + mat[3][1]);
784 dst4[2] = mat32;
785 dst4[3] = 1;
786 src2 += 2;
787 dst4 += 4;
788 }
789}
790
791static void map2_sd(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
792 int count, double* SK_RESTRICT dst4) {
793 for (int n = 0; n < count; ++n) {
794 dst4[0] = mat[0][0] * src2[0] + mat[3][0];
795 dst4[1] = mat[1][1] * src2[1] + mat[3][1];
796 dst4[2] = mat[3][2];
797 dst4[3] = 1;
798 src2 += 2;
799 dst4 += 4;
800 }
801}
802
803static void map2_af(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
804 int count, float* SK_RESTRICT dst4) {
805 double r;
806 for (int n = 0; n < count; ++n) {
807 double sx = src2[0];
808 double sy = src2[1];
809 r = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
810 dst4[0] = SkMScalarToFloat(r);
811 r = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
812 dst4[1] = SkMScalarToFloat(r);
813 r = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
814 dst4[2] = SkMScalarToFloat(r);
815 dst4[3] = 1;
816 src2 += 2;
817 dst4 += 4;
818 }
819}
820
821static void map2_ad(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
822 int count, double* SK_RESTRICT dst4) {
823 for (int n = 0; n < count; ++n) {
824 double sx = src2[0];
825 double sy = src2[1];
826 dst4[0] = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
827 dst4[1] = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
828 dst4[2] = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
829 dst4[3] = 1;
830 src2 += 2;
831 dst4 += 4;
832 }
833}
834
835static void map2_pf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
836 int count, float* SK_RESTRICT dst4) {
837 double r;
838 for (int n = 0; n < count; ++n) {
839 double sx = src2[0];
840 double sy = src2[1];
841 for (int i = 0; i < 4; i++) {
842 r = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
843 dst4[i] = SkMScalarToFloat(r);
844 }
845 src2 += 2;
846 dst4 += 4;
847 }
848}
849
850static void map2_pd(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
851 int count, double* SK_RESTRICT dst4) {
852 for (int n = 0; n < count; ++n) {
853 double sx = src2[0];
854 double sy = src2[1];
855 for (int i = 0; i < 4; i++) {
856 dst4[i] = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
857 }
858 src2 += 2;
859 dst4 += 4;
860 }
861}
862
863void SkMatrix44::map2(const float src2[], int count, float dst4[]) const {
864 static const Map2Procf gProc[] = {
865 map2_if, map2_tf, map2_sf, map2_sf, map2_af, map2_af, map2_af, map2_af
866 };
867
868 TypeMask mask = this->getType();
869 Map2Procf proc = (mask & kPerspective_Mask) ? map2_pf : gProc[mask];
870 proc(fMat, src2, count, dst4);
871}
872
873void SkMatrix44::map2(const double src2[], int count, double dst4[]) const {
874 static const Map2Procd gProc[] = {
875 map2_id, map2_td, map2_sd, map2_sd, map2_ad, map2_ad, map2_ad, map2_ad
876 };
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000877
reed@google.com99b5c7f2012-12-05 22:13:59 +0000878 TypeMask mask = this->getType();
879 Map2Procd proc = (mask & kPerspective_Mask) ? map2_pd : gProc[mask];
880 proc(fMat, src2, count, dst4);
881}
882
reed@google.com8260a892011-06-13 14:02:52 +0000883///////////////////////////////////////////////////////////////////////////////
884
885void SkMatrix44::dump() const {
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000886 static const char* format =
887 "[%g %g %g %g][%g %g %g %g][%g %g %g %g][%g %g %g %g]\n";
reed@google.com8260a892011-06-13 14:02:52 +0000888#if 0
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000889 SkDebugf(format,
reed@google.com8260a892011-06-13 14:02:52 +0000890 fMat[0][0], fMat[1][0], fMat[2][0], fMat[3][0],
891 fMat[0][1], fMat[1][1], fMat[2][1], fMat[3][1],
892 fMat[0][2], fMat[1][2], fMat[2][2], fMat[3][2],
893 fMat[0][3], fMat[1][3], fMat[2][3], fMat[3][3]);
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000894#else
895 SkDebugf(format,
896 fMat[0][0], fMat[0][1], fMat[0][2], fMat[0][3],
897 fMat[1][0], fMat[1][1], fMat[1][2], fMat[1][3],
898 fMat[2][0], fMat[2][1], fMat[2][2], fMat[2][3],
899 fMat[3][0], fMat[3][1], fMat[3][2], fMat[3][3]);
reed@google.com8260a892011-06-13 14:02:52 +0000900#endif
901}
902
903///////////////////////////////////////////////////////////////////////////////
904
reed@google.com7d683352012-12-03 21:19:52 +0000905// TODO: make this support src' perspective elements
906//
reed@google.com8260a892011-06-13 14:02:52 +0000907static void initFromMatrix(SkMScalar dst[4][4], const SkMatrix& src) {
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000908 dst[0][0] = SkScalarToMScalar(src[SkMatrix::kMScaleX]);
909 dst[1][0] = SkScalarToMScalar(src[SkMatrix::kMSkewX]);
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000910 dst[2][0] = 0;
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000911 dst[3][0] = SkScalarToMScalar(src[SkMatrix::kMTransX]);
912 dst[0][1] = SkScalarToMScalar(src[SkMatrix::kMSkewY]);
913 dst[1][1] = SkScalarToMScalar(src[SkMatrix::kMScaleY]);
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000914 dst[2][1] = 0;
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000915 dst[3][1] = SkScalarToMScalar(src[SkMatrix::kMTransY]);
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000916 dst[0][2] = 0;
917 dst[1][2] = 0;
918 dst[2][2] = 1;
919 dst[3][2] = 0;
920 dst[0][3] = 0;
921 dst[1][3] = 0;
922 dst[2][3] = 0;
923 dst[3][3] = 1;
reed@google.com8260a892011-06-13 14:02:52 +0000924}
925
926SkMatrix44::SkMatrix44(const SkMatrix& src) {
927 initFromMatrix(fMat, src);
928}
929
930SkMatrix44& SkMatrix44::operator=(const SkMatrix& src) {
931 initFromMatrix(fMat, src);
reed@google.com7d683352012-12-03 21:19:52 +0000932
933 if (src.isIdentity()) {
934 this->setTypeMask(kIdentity_Mask);
935 } else {
936 this->dirtyTypeMask();
937 }
reed@google.com8260a892011-06-13 14:02:52 +0000938 return *this;
939}
940
reed@google.com7d683352012-12-03 21:19:52 +0000941// TODO: make this support our perspective elements
942//
reed@google.com8260a892011-06-13 14:02:52 +0000943SkMatrix44::operator SkMatrix() const {
944 SkMatrix dst;
945 dst.reset(); // setup our perspective correctly for identity
946
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000947 dst[SkMatrix::kMScaleX] = SkMScalarToScalar(fMat[0][0]);
948 dst[SkMatrix::kMSkewX] = SkMScalarToScalar(fMat[1][0]);
949 dst[SkMatrix::kMTransX] = SkMScalarToScalar(fMat[3][0]);
reed@google.com8260a892011-06-13 14:02:52 +0000950
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000951 dst[SkMatrix::kMSkewY] = SkMScalarToScalar(fMat[0][1]);
952 dst[SkMatrix::kMScaleY] = SkMScalarToScalar(fMat[1][1]);
953 dst[SkMatrix::kMTransY] = SkMScalarToScalar(fMat[3][1]);
reed@google.com8260a892011-06-13 14:02:52 +0000954
955 return dst;
956}