blob: c9247235db473a139c1ef4f04d44bb7e3c9927a9 [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
reed@google.com8260a892011-06-13 14:02:52 +0000409/** We always perform the calculation in doubles, to avoid prematurely losing
410 precision along the way. This relies on the compiler automatically
411 promoting our SkMScalar values to double (if needed).
412 */
413double SkMatrix44::determinant() const {
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000414 if (this->isIdentity()) {
415 return 1;
416 }
417 if (this->isScaleTranslate()) {
418 return fMat[0][0] * fMat[1][1] * fMat[2][2] * fMat[3][3];
419 }
420
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000421 double a00 = fMat[0][0];
422 double a01 = fMat[0][1];
423 double a02 = fMat[0][2];
424 double a03 = fMat[0][3];
425 double a10 = fMat[1][0];
426 double a11 = fMat[1][1];
427 double a12 = fMat[1][2];
428 double a13 = fMat[1][3];
429 double a20 = fMat[2][0];
430 double a21 = fMat[2][1];
431 double a22 = fMat[2][2];
432 double a23 = fMat[2][3];
433 double a30 = fMat[3][0];
434 double a31 = fMat[3][1];
435 double a32 = fMat[3][2];
436 double a33 = fMat[3][3];
437
438 double b00 = a00 * a11 - a01 * a10;
439 double b01 = a00 * a12 - a02 * a10;
440 double b02 = a00 * a13 - a03 * a10;
441 double b03 = a01 * a12 - a02 * a11;
442 double b04 = a01 * a13 - a03 * a11;
443 double b05 = a02 * a13 - a03 * a12;
444 double b06 = a20 * a31 - a21 * a30;
445 double b07 = a20 * a32 - a22 * a30;
446 double b08 = a20 * a33 - a23 * a30;
447 double b09 = a21 * a32 - a22 * a31;
448 double b10 = a21 * a33 - a23 * a31;
449 double b11 = a22 * a33 - a23 * a32;
450
451 // Calculate the determinant
452 return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
reed@google.com8260a892011-06-13 14:02:52 +0000453}
454
455///////////////////////////////////////////////////////////////////////////////
456
reed@google.com8260a892011-06-13 14:02:52 +0000457bool SkMatrix44::invert(SkMatrix44* inverse) const {
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000458 if (this->isIdentity()) {
reed@google.com7d683352012-12-03 21:19:52 +0000459 if (inverse) {
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000460 inverse->setIdentity();
reed@google.com7d683352012-12-03 21:19:52 +0000461 return true;
462 }
463 }
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000464 if (this->isTranslate()) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000465 if (inverse) {
466 inverse->setTranslate(-fMat[3][0], -fMat[3][1], -fMat[3][2]);
467 }
468 return true;
469 }
mike@reedtribe.orgf8b1ebc2012-12-10 03:27:47 +0000470 if (this->isScaleTranslate()) {
reed@google.com99b5c7f2012-12-05 22:13:59 +0000471 if (0 == fMat[0][0] * fMat[1][1] * fMat[2][2]) {
472 return false;
473 }
reed@google.com99b5c7f2012-12-05 22:13:59 +0000474
skia.committer@gmail.com772c4e62013-08-30 07:01:34 +0000475 if (inverse) {
476 double invXScale = 1 / fMat[0][0];
477 double invYScale = 1 / fMat[1][1];
478 double invZScale = 1 / fMat[2][2];
reed@google.com99b5c7f2012-12-05 22:13:59 +0000479
skia.committer@gmail.com772c4e62013-08-30 07:01:34 +0000480 inverse->fMat[0][0] = invXScale;
481 inverse->fMat[0][1] = 0;
482 inverse->fMat[0][2] = 0;
483 inverse->fMat[0][3] = 0;
484
485 inverse->fMat[1][0] = 0;
486 inverse->fMat[1][1] = invYScale;
487 inverse->fMat[1][2] = 0;
488 inverse->fMat[1][3] = 0;
489
490 inverse->fMat[2][0] = 0;
commit-bot@chromium.orgc33d6212013-08-29 15:34:50 +0000491 inverse->fMat[2][1] = 0;
skia.committer@gmail.com772c4e62013-08-30 07:01:34 +0000492 inverse->fMat[2][2] = invZScale;
493 inverse->fMat[2][3] = 0;
494
commit-bot@chromium.orgc33d6212013-08-29 15:34:50 +0000495 inverse->fMat[3][0] = -fMat[3][0] * invXScale;
496 inverse->fMat[3][1] = -fMat[3][1] * invYScale;
497 inverse->fMat[3][2] = -fMat[3][2] * invZScale;
498 inverse->fMat[3][3] = 1;
shawnsingh@chromium.orgb6823c12013-08-22 20:24:21 +0000499
commit-bot@chromium.orgc33d6212013-08-29 15:34:50 +0000500 inverse->setTypeMask(this->getType());
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000501 }
502
reed@google.com99b5c7f2012-12-05 22:13:59 +0000503 return true;
504 }
505
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000506 double a00 = fMat[0][0];
507 double a01 = fMat[0][1];
508 double a02 = fMat[0][2];
509 double a03 = fMat[0][3];
510 double a10 = fMat[1][0];
511 double a11 = fMat[1][1];
512 double a12 = fMat[1][2];
513 double a13 = fMat[1][3];
514 double a20 = fMat[2][0];
515 double a21 = fMat[2][1];
516 double a22 = fMat[2][2];
517 double a23 = fMat[2][3];
518 double a30 = fMat[3][0];
519 double a31 = fMat[3][1];
520 double a32 = fMat[3][2];
521 double a33 = fMat[3][3];
522
shawnsingh@chromium.orgb6823c12013-08-22 20:24:21 +0000523 if (!(this->getType() & kPerspective_Mask)) {
524 // If we know the matrix has no perspective, then the perspective
525 // component is (0, 0, 0, 1). We can use this information to save a lot
526 // of arithmetic that would otherwise be spent to compute the inverse
527 // of a general matrix.
528
529 SkASSERT(a03 == 0);
530 SkASSERT(a13 == 0);
531 SkASSERT(a23 == 0);
532 SkASSERT(a33 == 1);
533
534 double b00 = a00 * a11 - a01 * a10;
535 double b01 = a00 * a12 - a02 * a10;
536 double b03 = a01 * a12 - a02 * a11;
537 double b06 = a20 * a31 - a21 * a30;
538 double b07 = a20 * a32 - a22 * a30;
539 double b08 = a20;
540 double b09 = a21 * a32 - a22 * a31;
541 double b10 = a21;
542 double b11 = a22;
543
544 // Calculate the determinant
545 double det = b00 * b11 - b01 * b10 + b03 * b08;
546
547 double invdet = 1.0 / det;
548 // If det is zero, we want to return false. However, we also want to return false
549 // if 1/det overflows to infinity (i.e. det is denormalized). Both of these are
550 // handled by checking that 1/det is finite.
551 if (!sk_float_isfinite(invdet)) {
552 return false;
553 }
554 if (NULL == inverse) {
555 return true;
556 }
557
558 b00 *= invdet;
559 b01 *= invdet;
560 b03 *= invdet;
561 b06 *= invdet;
562 b07 *= invdet;
563 b08 *= invdet;
564 b09 *= invdet;
565 b10 *= invdet;
566 b11 *= invdet;
567
568 inverse->fMat[0][0] = SkDoubleToMScalar(a11 * b11 - a12 * b10);
569 inverse->fMat[0][1] = SkDoubleToMScalar(a02 * b10 - a01 * b11);
570 inverse->fMat[0][2] = SkDoubleToMScalar(b03);
571 inverse->fMat[0][3] = 0;
572 inverse->fMat[1][0] = SkDoubleToMScalar(a12 * b08 - a10 * b11);
573 inverse->fMat[1][1] = SkDoubleToMScalar(a00 * b11 - a02 * b08);
574 inverse->fMat[1][2] = SkDoubleToMScalar(-b01);
575 inverse->fMat[1][3] = 0;
576 inverse->fMat[2][0] = SkDoubleToMScalar(a10 * b10 - a11 * b08);
577 inverse->fMat[2][1] = SkDoubleToMScalar(a01 * b08 - a00 * b10);
578 inverse->fMat[2][2] = SkDoubleToMScalar(b00);
579 inverse->fMat[2][3] = 0;
580 inverse->fMat[3][0] = SkDoubleToMScalar(a11 * b07 - a10 * b09 - a12 * b06);
581 inverse->fMat[3][1] = SkDoubleToMScalar(a00 * b09 - a01 * b07 + a02 * b06);
582 inverse->fMat[3][2] = SkDoubleToMScalar(a31 * b01 - a30 * b03 - a32 * b00);
583 inverse->fMat[3][3] = 1;
584
585 inverse->setTypeMask(this->getType());
586 return true;
587 }
588
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000589 double b00 = a00 * a11 - a01 * a10;
590 double b01 = a00 * a12 - a02 * a10;
591 double b02 = a00 * a13 - a03 * a10;
592 double b03 = a01 * a12 - a02 * a11;
593 double b04 = a01 * a13 - a03 * a11;
594 double b05 = a02 * a13 - a03 * a12;
595 double b06 = a20 * a31 - a21 * a30;
596 double b07 = a20 * a32 - a22 * a30;
597 double b08 = a20 * a33 - a23 * a30;
598 double b09 = a21 * a32 - a22 * a31;
599 double b10 = a21 * a33 - a23 * a31;
600 double b11 = a22 * a33 - a23 * a32;
601
602 // Calculate the determinant
603 double det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
604
commit-bot@chromium.orgf02f0782013-08-20 15:25:04 +0000605 double invdet = 1.0 / det;
606 // If det is zero, we want to return false. However, we also want to return false
607 // if 1/det overflows to infinity (i.e. det is denormalized). Both of these are
608 // handled by checking that 1/det is finite.
609 if (!sk_float_isfinite(invdet)) {
reed@google.com8260a892011-06-13 14:02:52 +0000610 return false;
611 }
612 if (NULL == inverse) {
613 return true;
614 }
615
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000616 b00 *= invdet;
617 b01 *= invdet;
618 b02 *= invdet;
619 b03 *= invdet;
620 b04 *= invdet;
621 b05 *= invdet;
622 b06 *= invdet;
623 b07 *= invdet;
624 b08 *= invdet;
625 b09 *= invdet;
626 b10 *= invdet;
627 b11 *= invdet;
reed@google.com8260a892011-06-13 14:02:52 +0000628
tomhudson@google.com9973a8a2012-12-13 09:55:42 +0000629 inverse->fMat[0][0] = SkDoubleToMScalar(a11 * b11 - a12 * b10 + a13 * b09);
630 inverse->fMat[0][1] = SkDoubleToMScalar(a02 * b10 - a01 * b11 - a03 * b09);
631 inverse->fMat[0][2] = SkDoubleToMScalar(a31 * b05 - a32 * b04 + a33 * b03);
632 inverse->fMat[0][3] = SkDoubleToMScalar(a22 * b04 - a21 * b05 - a23 * b03);
633 inverse->fMat[1][0] = SkDoubleToMScalar(a12 * b08 - a10 * b11 - a13 * b07);
634 inverse->fMat[1][1] = SkDoubleToMScalar(a00 * b11 - a02 * b08 + a03 * b07);
635 inverse->fMat[1][2] = SkDoubleToMScalar(a32 * b02 - a30 * b05 - a33 * b01);
636 inverse->fMat[1][3] = SkDoubleToMScalar(a20 * b05 - a22 * b02 + a23 * b01);
637 inverse->fMat[2][0] = SkDoubleToMScalar(a10 * b10 - a11 * b08 + a13 * b06);
638 inverse->fMat[2][1] = SkDoubleToMScalar(a01 * b08 - a00 * b10 - a03 * b06);
639 inverse->fMat[2][2] = SkDoubleToMScalar(a30 * b04 - a31 * b02 + a33 * b00);
640 inverse->fMat[2][3] = SkDoubleToMScalar(a21 * b02 - a20 * b04 - a23 * b00);
641 inverse->fMat[3][0] = SkDoubleToMScalar(a11 * b07 - a10 * b09 - a12 * b06);
642 inverse->fMat[3][1] = SkDoubleToMScalar(a00 * b09 - a01 * b07 + a02 * b06);
643 inverse->fMat[3][2] = SkDoubleToMScalar(a31 * b01 - a30 * b03 - a32 * b00);
644 inverse->fMat[3][3] = SkDoubleToMScalar(a20 * b03 - a21 * b01 + a22 * b00);
645 inverse->dirtyTypeMask();
reed@google.com8260a892011-06-13 14:02:52 +0000646
reed@google.com8260a892011-06-13 14:02:52 +0000647 return true;
648}
649
650///////////////////////////////////////////////////////////////////////////////
651
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000652void SkMatrix44::transpose() {
653 SkTSwap(fMat[0][1], fMat[1][0]);
654 SkTSwap(fMat[0][2], fMat[2][0]);
655 SkTSwap(fMat[0][3], fMat[3][0]);
656 SkTSwap(fMat[1][2], fMat[2][1]);
657 SkTSwap(fMat[1][3], fMat[3][1]);
658 SkTSwap(fMat[2][3], fMat[3][2]);
reed@google.com7d683352012-12-03 21:19:52 +0000659
660 if (!this->isTriviallyIdentity()) {
661 this->dirtyTypeMask();
662 }
vollick@chromium.org9b21c252012-11-14 21:33:55 +0000663}
664
665///////////////////////////////////////////////////////////////////////////////
666
reed@google.com1ea95be2012-11-09 21:39:48 +0000667void SkMatrix44::mapScalars(const SkScalar src[4], SkScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000668 SkScalar storage[4];
669 SkScalar* result = (src == dst) ? storage : dst;
670
reed@google.com8260a892011-06-13 14:02:52 +0000671 for (int i = 0; i < 4; i++) {
672 SkMScalar value = 0;
673 for (int j = 0; j < 4; j++) {
674 value += fMat[j][i] * src[j];
675 }
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000676 result[i] = SkMScalarToScalar(value);
reed@google.com8260a892011-06-13 14:02:52 +0000677 }
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000678
reed@google.com7d683352012-12-03 21:19:52 +0000679 if (storage == result) {
680 memcpy(dst, storage, sizeof(storage));
681 }
reed@google.com8260a892011-06-13 14:02:52 +0000682}
683
reed@google.com1ea95be2012-11-09 21:39:48 +0000684#ifdef SK_MSCALAR_IS_DOUBLE
reed@google.com7d683352012-12-03 21:19:52 +0000685
reed@google.com1ea95be2012-11-09 21:39:48 +0000686void SkMatrix44::mapMScalars(const SkMScalar src[4], SkMScalar dst[4]) const {
reed@google.com7d683352012-12-03 21:19:52 +0000687 SkMScalar storage[4];
688 SkMScalar* result = (src == dst) ? storage : dst;
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000689
reed@google.com1ea95be2012-11-09 21:39:48 +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 }
reed@google.com7d683352012-12-03 21:19:52 +0000695 result[i] = value;
reed@google.com1ea95be2012-11-09 21:39:48 +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.com1ea95be2012-11-09 21:39:48 +0000701}
reed@google.com7d683352012-12-03 21:19:52 +0000702
reed@google.com1ea95be2012-11-09 21:39:48 +0000703#endif
704
reed@google.com99b5c7f2012-12-05 22:13:59 +0000705typedef void (*Map2Procf)(const SkMScalar mat[][4], const float src2[], int count, float dst4[]);
706typedef void (*Map2Procd)(const SkMScalar mat[][4], const double src2[], int count, double dst4[]);
707
708static void map2_if(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
709 int count, float* SK_RESTRICT dst4) {
710 for (int i = 0; i < count; ++i) {
711 dst4[0] = src2[0];
712 dst4[1] = src2[1];
713 dst4[2] = 0;
714 dst4[3] = 1;
715 src2 += 2;
716 dst4 += 4;
717 }
718}
719
720static void map2_id(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
721 int count, double* SK_RESTRICT dst4) {
722 for (int i = 0; i < count; ++i) {
723 dst4[0] = src2[0];
724 dst4[1] = src2[1];
725 dst4[2] = 0;
726 dst4[3] = 1;
727 src2 += 2;
728 dst4 += 4;
729 }
730}
731
732static void map2_tf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
733 int count, float* SK_RESTRICT dst4) {
734 const float mat30 = SkMScalarToFloat(mat[3][0]);
735 const float mat31 = SkMScalarToFloat(mat[3][1]);
736 const float mat32 = SkMScalarToFloat(mat[3][2]);
737 for (int n = 0; n < count; ++n) {
738 dst4[0] = src2[0] + mat30;
739 dst4[1] = src2[1] + mat31;
740 dst4[2] = mat32;
741 dst4[3] = 1;
742 src2 += 2;
743 dst4 += 4;
744 }
745}
746
747static void map2_td(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
748 int count, double* SK_RESTRICT dst4) {
749 for (int n = 0; n < count; ++n) {
750 dst4[0] = src2[0] + mat[3][0];
751 dst4[1] = src2[1] + mat[3][1];
752 dst4[2] = mat[3][2];
753 dst4[3] = 1;
754 src2 += 2;
755 dst4 += 4;
756 }
757}
758
759static void map2_sf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
760 int count, float* SK_RESTRICT dst4) {
761 const float mat32 = SkMScalarToFloat(mat[3][2]);
762 for (int n = 0; n < count; ++n) {
763 dst4[0] = SkMScalarToFloat(mat[0][0] * src2[0] + mat[3][0]);
764 dst4[1] = SkMScalarToFloat(mat[1][1] * src2[1] + mat[3][1]);
765 dst4[2] = mat32;
766 dst4[3] = 1;
767 src2 += 2;
768 dst4 += 4;
769 }
770}
771
772static void map2_sd(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
773 int count, double* SK_RESTRICT dst4) {
774 for (int n = 0; n < count; ++n) {
775 dst4[0] = mat[0][0] * src2[0] + mat[3][0];
776 dst4[1] = mat[1][1] * src2[1] + mat[3][1];
777 dst4[2] = mat[3][2];
778 dst4[3] = 1;
779 src2 += 2;
780 dst4 += 4;
781 }
782}
783
784static void map2_af(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
785 int count, float* SK_RESTRICT dst4) {
786 double r;
787 for (int n = 0; n < count; ++n) {
788 double sx = src2[0];
789 double sy = src2[1];
790 r = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
791 dst4[0] = SkMScalarToFloat(r);
792 r = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
793 dst4[1] = SkMScalarToFloat(r);
794 r = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
795 dst4[2] = SkMScalarToFloat(r);
796 dst4[3] = 1;
797 src2 += 2;
798 dst4 += 4;
799 }
800}
801
802static void map2_ad(const SkMScalar mat[][4], const double* SK_RESTRICT src2,
803 int count, double* SK_RESTRICT dst4) {
804 for (int n = 0; n < count; ++n) {
805 double sx = src2[0];
806 double sy = src2[1];
807 dst4[0] = mat[0][0] * sx + mat[1][0] * sy + mat[3][0];
808 dst4[1] = mat[0][1] * sx + mat[1][1] * sy + mat[3][1];
809 dst4[2] = mat[0][2] * sx + mat[1][2] * sy + mat[3][2];
810 dst4[3] = 1;
811 src2 += 2;
812 dst4 += 4;
813 }
814}
815
816static void map2_pf(const SkMScalar mat[][4], const float* SK_RESTRICT src2,
817 int count, float* SK_RESTRICT dst4) {
818 double r;
819 for (int n = 0; n < count; ++n) {
820 double sx = src2[0];
821 double sy = src2[1];
822 for (int i = 0; i < 4; i++) {
823 r = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
824 dst4[i] = SkMScalarToFloat(r);
825 }
826 src2 += 2;
827 dst4 += 4;
828 }
829}
830
831static void map2_pd(const SkMScalar 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 for (int i = 0; i < 4; i++) {
837 dst4[i] = mat[0][i] * sx + mat[1][i] * sy + mat[3][i];
838 }
839 src2 += 2;
840 dst4 += 4;
841 }
842}
843
844void SkMatrix44::map2(const float src2[], int count, float dst4[]) const {
845 static const Map2Procf gProc[] = {
846 map2_if, map2_tf, map2_sf, map2_sf, map2_af, map2_af, map2_af, map2_af
847 };
848
849 TypeMask mask = this->getType();
850 Map2Procf proc = (mask & kPerspective_Mask) ? map2_pf : gProc[mask];
851 proc(fMat, src2, count, dst4);
852}
853
854void SkMatrix44::map2(const double src2[], int count, double dst4[]) const {
855 static const Map2Procd gProc[] = {
856 map2_id, map2_td, map2_sd, map2_sd, map2_ad, map2_ad, map2_ad, map2_ad
857 };
skia.committer@gmail.com0264fb42012-12-06 02:01:25 +0000858
reed@google.com99b5c7f2012-12-05 22:13:59 +0000859 TypeMask mask = this->getType();
860 Map2Procd proc = (mask & kPerspective_Mask) ? map2_pd : gProc[mask];
861 proc(fMat, src2, count, dst4);
862}
863
reed@google.com8260a892011-06-13 14:02:52 +0000864///////////////////////////////////////////////////////////////////////////////
865
866void SkMatrix44::dump() const {
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000867 static const char* format =
868 "[%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 +0000869#if 0
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000870 SkDebugf(format,
reed@google.com8260a892011-06-13 14:02:52 +0000871 fMat[0][0], fMat[1][0], fMat[2][0], fMat[3][0],
872 fMat[0][1], fMat[1][1], fMat[2][1], fMat[3][1],
873 fMat[0][2], fMat[1][2], fMat[2][2], fMat[3][2],
874 fMat[0][3], fMat[1][3], fMat[2][3], fMat[3][3]);
tomhudson@google.com9ac4a892011-06-28 13:53:13 +0000875#else
876 SkDebugf(format,
877 fMat[0][0], fMat[0][1], fMat[0][2], fMat[0][3],
878 fMat[1][0], fMat[1][1], fMat[1][2], fMat[1][3],
879 fMat[2][0], fMat[2][1], fMat[2][2], fMat[2][3],
880 fMat[3][0], fMat[3][1], fMat[3][2], fMat[3][3]);
reed@google.com8260a892011-06-13 14:02:52 +0000881#endif
882}
883
884///////////////////////////////////////////////////////////////////////////////
885
886static void initFromMatrix(SkMScalar dst[4][4], const SkMatrix& src) {
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000887 dst[0][0] = SkScalarToMScalar(src[SkMatrix::kMScaleX]);
888 dst[1][0] = SkScalarToMScalar(src[SkMatrix::kMSkewX]);
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000889 dst[2][0] = 0;
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000890 dst[3][0] = SkScalarToMScalar(src[SkMatrix::kMTransX]);
891 dst[0][1] = SkScalarToMScalar(src[SkMatrix::kMSkewY]);
892 dst[1][1] = SkScalarToMScalar(src[SkMatrix::kMScaleY]);
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000893 dst[2][1] = 0;
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000894 dst[3][1] = SkScalarToMScalar(src[SkMatrix::kMTransY]);
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000895 dst[0][2] = 0;
896 dst[1][2] = 0;
897 dst[2][2] = 1;
898 dst[3][2] = 0;
commit-bot@chromium.org722555b2013-10-05 01:16:30 +0000899 dst[0][3] = SkScalarToMScalar(src[SkMatrix::kMPersp0]);
900 dst[1][3] = SkScalarToMScalar(src[SkMatrix::kMPersp1]);
shawnsingh@chromium.org5a6cd352013-08-28 18:55:25 +0000901 dst[2][3] = 0;
commit-bot@chromium.org722555b2013-10-05 01:16:30 +0000902 dst[3][3] = SkScalarToMScalar(src[SkMatrix::kMPersp2]);
reed@google.com8260a892011-06-13 14:02:52 +0000903}
904
905SkMatrix44::SkMatrix44(const SkMatrix& src) {
906 initFromMatrix(fMat, src);
907}
908
909SkMatrix44& SkMatrix44::operator=(const SkMatrix& src) {
910 initFromMatrix(fMat, src);
reed@google.com7d683352012-12-03 21:19:52 +0000911
912 if (src.isIdentity()) {
913 this->setTypeMask(kIdentity_Mask);
914 } else {
915 this->dirtyTypeMask();
916 }
reed@google.com8260a892011-06-13 14:02:52 +0000917 return *this;
918}
919
920SkMatrix44::operator SkMatrix() const {
921 SkMatrix dst;
reed@google.com8260a892011-06-13 14:02:52 +0000922
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000923 dst[SkMatrix::kMScaleX] = SkMScalarToScalar(fMat[0][0]);
924 dst[SkMatrix::kMSkewX] = SkMScalarToScalar(fMat[1][0]);
925 dst[SkMatrix::kMTransX] = SkMScalarToScalar(fMat[3][0]);
reed@google.com8260a892011-06-13 14:02:52 +0000926
bsalomon@google.com72e49b82011-10-27 21:47:03 +0000927 dst[SkMatrix::kMSkewY] = SkMScalarToScalar(fMat[0][1]);
928 dst[SkMatrix::kMScaleY] = SkMScalarToScalar(fMat[1][1]);
929 dst[SkMatrix::kMTransY] = SkMScalarToScalar(fMat[3][1]);
reed@google.com8260a892011-06-13 14:02:52 +0000930
commit-bot@chromium.org722555b2013-10-05 01:16:30 +0000931 dst[SkMatrix::kMPersp0] = SkMScalarToScalar(fMat[0][3]);
932 dst[SkMatrix::kMPersp1] = SkMScalarToScalar(fMat[1][3]);
933 dst[SkMatrix::kMPersp2] = SkMScalarToScalar(fMat[3][3]);
934
reed@google.com8260a892011-06-13 14:02:52 +0000935 return dst;
936}