• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2005, 2006 Apple Computer, Inc.  All rights reserved.
3  * Copyright (C) 2009 Torch Mobile, Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include "config.h"
28 #include "TransformationMatrix.h"
29 
30 #include "FloatPoint3D.h"
31 #include "FloatRect.h"
32 #include "FloatQuad.h"
33 #include "IntRect.h"
34 
35 #include <wtf/Assertions.h>
36 #include <wtf/MathExtras.h>
37 
38 namespace WebCore {
39 
40 //
41 // Supporting Math Functions
42 //
43 // This is a set of function from various places (attributed inline) to do things like
44 // inversion and decomposition of a 4x4 matrix. They are used throughout the code
45 //
46 
47 //
48 // Adapted from Matrix Inversion by Richard Carling, Graphics Gems <http://tog.acm.org/GraphicsGems/index.html>.
49 
50 // EULA: The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code
51 // as your own and resell it. Using the code is permitted in any program, product, or library, non-commercial
52 // or commercial. Giving credit is not required, though is a nice gesture. The code comes as-is, and if there
53 // are any flaws or problems with any Gems code, nobody involved with Gems - authors, editors, publishers, or
54 // webmasters - are to be held responsible. Basically, don't be a jerk, and remember that anything free comes
55 // with no guarantee.
56 
57 typedef double Vector4[4];
58 typedef double Vector3[3];
59 
60 const double SMALL_NUMBER = 1.e-8;
61 
62 // inverse(original_matrix, inverse_matrix)
63 //
64 // calculate the inverse of a 4x4 matrix
65 //
66 // -1
67 // A  = ___1__ adjoint A
68 //       det A
69 
70 //  double = determinant2x2(double a, double b, double c, double d)
71 //
72 //  calculate the determinant of a 2x2 matrix.
73 
determinant2x2(double a,double b,double c,double d)74 static double determinant2x2(double a, double b, double c, double d)
75 {
76     return a * d - b * c;
77 }
78 
79 //  double = determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3)
80 //
81 //  Calculate the determinant of a 3x3 matrix
82 //  in the form
83 //
84 //      | a1,  b1,  c1 |
85 //      | a2,  b2,  c2 |
86 //      | a3,  b3,  c3 |
87 
determinant3x3(double a1,double a2,double a3,double b1,double b2,double b3,double c1,double c2,double c3)88 static double determinant3x3(double a1, double a2, double a3, double b1, double b2, double b3, double c1, double c2, double c3)
89 {
90     return a1 * determinant2x2(b2, b3, c2, c3)
91          - b1 * determinant2x2(a2, a3, c2, c3)
92          + c1 * determinant2x2(a2, a3, b2, b3);
93 }
94 
95 //  double = determinant4x4(matrix)
96 //
97 //  calculate the determinant of a 4x4 matrix.
98 
determinant4x4(const TransformationMatrix::Matrix4 & m)99 static double determinant4x4(const TransformationMatrix::Matrix4& m)
100 {
101     // Assign to individual variable names to aid selecting
102     // correct elements
103 
104     double a1 = m[0][0];
105     double b1 = m[0][1];
106     double c1 = m[0][2];
107     double d1 = m[0][3];
108 
109     double a2 = m[1][0];
110     double b2 = m[1][1];
111     double c2 = m[1][2];
112     double d2 = m[1][3];
113 
114     double a3 = m[2][0];
115     double b3 = m[2][1];
116     double c3 = m[2][2];
117     double d3 = m[2][3];
118 
119     double a4 = m[3][0];
120     double b4 = m[3][1];
121     double c4 = m[3][2];
122     double d4 = m[3][3];
123 
124     return a1 * determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4)
125          - b1 * determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4)
126          + c1 * determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4)
127          - d1 * determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);
128 }
129 
130 // adjoint( original_matrix, inverse_matrix )
131 //
132 //   calculate the adjoint of a 4x4 matrix
133 //
134 //    Let  a   denote the minor determinant of matrix A obtained by
135 //         ij
136 //
137 //    deleting the ith row and jth column from A.
138 //
139 //                  i+j
140 //   Let  b   = (-1)    a
141 //        ij            ji
142 //
143 //  The matrix B = (b  ) is the adjoint of A
144 //                   ij
145 
adjoint(const TransformationMatrix::Matrix4 & matrix,TransformationMatrix::Matrix4 & result)146 static void adjoint(const TransformationMatrix::Matrix4& matrix, TransformationMatrix::Matrix4& result)
147 {
148     // Assign to individual variable names to aid
149     // selecting correct values
150     double a1 = matrix[0][0];
151     double b1 = matrix[0][1];
152     double c1 = matrix[0][2];
153     double d1 = matrix[0][3];
154 
155     double a2 = matrix[1][0];
156     double b2 = matrix[1][1];
157     double c2 = matrix[1][2];
158     double d2 = matrix[1][3];
159 
160     double a3 = matrix[2][0];
161     double b3 = matrix[2][1];
162     double c3 = matrix[2][2];
163     double d3 = matrix[2][3];
164 
165     double a4 = matrix[3][0];
166     double b4 = matrix[3][1];
167     double c4 = matrix[3][2];
168     double d4 = matrix[3][3];
169 
170     // Row column labeling reversed since we transpose rows & columns
171     result[0][0]  =   determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4);
172     result[1][0]  = - determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4);
173     result[2][0]  =   determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4);
174     result[3][0]  = - determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);
175 
176     result[0][1]  = - determinant3x3(b1, b3, b4, c1, c3, c4, d1, d3, d4);
177     result[1][1]  =   determinant3x3(a1, a3, a4, c1, c3, c4, d1, d3, d4);
178     result[2][1]  = - determinant3x3(a1, a3, a4, b1, b3, b4, d1, d3, d4);
179     result[3][1]  =   determinant3x3(a1, a3, a4, b1, b3, b4, c1, c3, c4);
180 
181     result[0][2]  =   determinant3x3(b1, b2, b4, c1, c2, c4, d1, d2, d4);
182     result[1][2]  = - determinant3x3(a1, a2, a4, c1, c2, c4, d1, d2, d4);
183     result[2][2]  =   determinant3x3(a1, a2, a4, b1, b2, b4, d1, d2, d4);
184     result[3][2]  = - determinant3x3(a1, a2, a4, b1, b2, b4, c1, c2, c4);
185 
186     result[0][3]  = - determinant3x3(b1, b2, b3, c1, c2, c3, d1, d2, d3);
187     result[1][3]  =   determinant3x3(a1, a2, a3, c1, c2, c3, d1, d2, d3);
188     result[2][3]  = - determinant3x3(a1, a2, a3, b1, b2, b3, d1, d2, d3);
189     result[3][3]  =   determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3);
190 }
191 
192 // Returns false if the matrix is not invertible
inverse(const TransformationMatrix::Matrix4 & matrix,TransformationMatrix::Matrix4 & result)193 static bool inverse(const TransformationMatrix::Matrix4& matrix, TransformationMatrix::Matrix4& result)
194 {
195     // Calculate the adjoint matrix
196     adjoint(matrix, result);
197 
198     // Calculate the 4x4 determinant
199     // If the determinant is zero,
200     // then the inverse matrix is not unique.
201     double det = determinant4x4(matrix);
202 
203     if (fabs(det) < SMALL_NUMBER)
204         return false;
205 
206     // Scale the adjoint matrix to get the inverse
207 
208     for (int i = 0; i < 4; i++)
209         for (int j = 0; j < 4; j++)
210             result[i][j] = result[i][j] / det;
211 
212     return true;
213 }
214 
215 // End of code adapted from Matrix Inversion by Richard Carling
216 
217 // Perform a decomposition on the passed matrix, return false if unsuccessful
218 // From Graphics Gems: unmatrix.c
219 
220 // Transpose rotation portion of matrix a, return b
transposeMatrix4(const TransformationMatrix::Matrix4 & a,TransformationMatrix::Matrix4 & b)221 static void transposeMatrix4(const TransformationMatrix::Matrix4& a, TransformationMatrix::Matrix4& b)
222 {
223     for (int i = 0; i < 4; i++)
224         for (int j = 0; j < 4; j++)
225             b[i][j] = a[j][i];
226 }
227 
228 // Multiply a homogeneous point by a matrix and return the transformed point
v4MulPointByMatrix(const Vector4 p,const TransformationMatrix::Matrix4 & m,Vector4 result)229 static void v4MulPointByMatrix(const Vector4 p, const TransformationMatrix::Matrix4& m, Vector4 result)
230 {
231     result[0] = (p[0] * m[0][0]) + (p[1] * m[1][0]) +
232                 (p[2] * m[2][0]) + (p[3] * m[3][0]);
233     result[1] = (p[0] * m[0][1]) + (p[1] * m[1][1]) +
234                 (p[2] * m[2][1]) + (p[3] * m[3][1]);
235     result[2] = (p[0] * m[0][2]) + (p[1] * m[1][2]) +
236                 (p[2] * m[2][2]) + (p[3] * m[3][2]);
237     result[3] = (p[0] * m[0][3]) + (p[1] * m[1][3]) +
238                 (p[2] * m[2][3]) + (p[3] * m[3][3]);
239 }
240 
v3Length(Vector3 a)241 static double v3Length(Vector3 a)
242 {
243     return sqrt((a[0] * a[0]) + (a[1] * a[1]) + (a[2] * a[2]));
244 }
245 
v3Scale(Vector3 v,double desiredLength)246 static void v3Scale(Vector3 v, double desiredLength)
247 {
248     double len = v3Length(v);
249     if (len != 0) {
250         double l = desiredLength / len;
251         v[0] *= l;
252         v[1] *= l;
253         v[2] *= l;
254     }
255 }
256 
v3Dot(const Vector3 a,const Vector3 b)257 static double v3Dot(const Vector3 a, const Vector3 b)
258 {
259     return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]);
260 }
261 
262 // Make a linear combination of two vectors and return the result.
263 // result = (a * ascl) + (b * bscl)
v3Combine(const Vector3 a,const Vector3 b,Vector3 result,double ascl,double bscl)264 static void v3Combine(const Vector3 a, const Vector3 b, Vector3 result, double ascl, double bscl)
265 {
266     result[0] = (ascl * a[0]) + (bscl * b[0]);
267     result[1] = (ascl * a[1]) + (bscl * b[1]);
268     result[2] = (ascl * a[2]) + (bscl * b[2]);
269 }
270 
271 // Return the cross product result = a cross b */
v3Cross(const Vector3 a,const Vector3 b,Vector3 result)272 static void v3Cross(const Vector3 a, const Vector3 b, Vector3 result)
273 {
274     result[0] = (a[1] * b[2]) - (a[2] * b[1]);
275     result[1] = (a[2] * b[0]) - (a[0] * b[2]);
276     result[2] = (a[0] * b[1]) - (a[1] * b[0]);
277 }
278 
decompose(const TransformationMatrix::Matrix4 & mat,TransformationMatrix::DecomposedType & result)279 static bool decompose(const TransformationMatrix::Matrix4& mat, TransformationMatrix::DecomposedType& result)
280 {
281     TransformationMatrix::Matrix4 localMatrix;
282     memcpy(localMatrix, mat, sizeof(TransformationMatrix::Matrix4));
283 
284     // Normalize the matrix.
285     if (localMatrix[3][3] == 0)
286         return false;
287 
288     int i, j;
289     for (i = 0; i < 4; i++)
290         for (j = 0; j < 4; j++)
291             localMatrix[i][j] /= localMatrix[3][3];
292 
293     // perspectiveMatrix is used to solve for perspective, but it also provides
294     // an easy way to test for singularity of the upper 3x3 component.
295     TransformationMatrix::Matrix4 perspectiveMatrix;
296     memcpy(perspectiveMatrix, localMatrix, sizeof(TransformationMatrix::Matrix4));
297     for (i = 0; i < 3; i++)
298         perspectiveMatrix[i][3] = 0;
299     perspectiveMatrix[3][3] = 1;
300 
301     if (determinant4x4(perspectiveMatrix) == 0)
302         return false;
303 
304     // First, isolate perspective.  This is the messiest.
305     if (localMatrix[0][3] != 0 || localMatrix[1][3] != 0 || localMatrix[2][3] != 0) {
306         // rightHandSide is the right hand side of the equation.
307         Vector4 rightHandSide;
308         rightHandSide[0] = localMatrix[0][3];
309         rightHandSide[1] = localMatrix[1][3];
310         rightHandSide[2] = localMatrix[2][3];
311         rightHandSide[3] = localMatrix[3][3];
312 
313         // Solve the equation by inverting perspectiveMatrix and multiplying
314         // rightHandSide by the inverse.  (This is the easiest way, not
315         // necessarily the best.)
316         TransformationMatrix::Matrix4 inversePerspectiveMatrix, transposedInversePerspectiveMatrix;
317         inverse(perspectiveMatrix, inversePerspectiveMatrix);
318         transposeMatrix4(inversePerspectiveMatrix, transposedInversePerspectiveMatrix);
319 
320         Vector4 perspectivePoint;
321         v4MulPointByMatrix(rightHandSide, transposedInversePerspectiveMatrix, perspectivePoint);
322 
323         result.perspectiveX = perspectivePoint[0];
324         result.perspectiveY = perspectivePoint[1];
325         result.perspectiveZ = perspectivePoint[2];
326         result.perspectiveW = perspectivePoint[3];
327 
328         // Clear the perspective partition
329         localMatrix[0][3] = localMatrix[1][3] = localMatrix[2][3] = 0;
330         localMatrix[3][3] = 1;
331     } else {
332         // No perspective.
333         result.perspectiveX = result.perspectiveY = result.perspectiveZ = 0;
334         result.perspectiveW = 1;
335     }
336 
337     // Next take care of translation (easy).
338     result.translateX = localMatrix[3][0];
339     localMatrix[3][0] = 0;
340     result.translateY = localMatrix[3][1];
341     localMatrix[3][1] = 0;
342     result.translateZ = localMatrix[3][2];
343     localMatrix[3][2] = 0;
344 
345     // Vector4 type and functions need to be added to the common set.
346     Vector3 row[3], pdum3;
347 
348     // Now get scale and shear.
349     for (i = 0; i < 3; i++) {
350         row[i][0] = localMatrix[i][0];
351         row[i][1] = localMatrix[i][1];
352         row[i][2] = localMatrix[i][2];
353     }
354 
355     // Compute X scale factor and normalize first row.
356     result.scaleX = v3Length(row[0]);
357     v3Scale(row[0], 1.0);
358 
359     // Compute XY shear factor and make 2nd row orthogonal to 1st.
360     result.skewXY = v3Dot(row[0], row[1]);
361     v3Combine(row[1], row[0], row[1], 1.0, -result.skewXY);
362 
363     // Now, compute Y scale and normalize 2nd row.
364     result.scaleY = v3Length(row[1]);
365     v3Scale(row[1], 1.0);
366     result.skewXY /= result.scaleY;
367 
368     // Compute XZ and YZ shears, orthogonalize 3rd row.
369     result.skewXZ = v3Dot(row[0], row[2]);
370     v3Combine(row[2], row[0], row[2], 1.0, -result.skewXZ);
371     result.skewYZ = v3Dot(row[1], row[2]);
372     v3Combine(row[2], row[1], row[2], 1.0, -result.skewYZ);
373 
374     // Next, get Z scale and normalize 3rd row.
375     result.scaleZ = v3Length(row[2]);
376     v3Scale(row[2], 1.0);
377     result.skewXZ /= result.scaleZ;
378     result.skewYZ /= result.scaleZ;
379 
380     // At this point, the matrix (in rows[]) is orthonormal.
381     // Check for a coordinate system flip.  If the determinant
382     // is -1, then negate the matrix and the scaling factors.
383     v3Cross(row[1], row[2], pdum3);
384     if (v3Dot(row[0], pdum3) < 0) {
385         for (i = 0; i < 3; i++) {
386             result.scaleX *= -1;
387             row[i][0] *= -1;
388             row[i][1] *= -1;
389             row[i][2] *= -1;
390         }
391     }
392 
393     // Now, get the rotations out, as described in the gem.
394 
395     // FIXME - Add the ability to return either quaternions (which are
396     // easier to recompose with) or Euler angles (rx, ry, rz), which
397     // are easier for authors to deal with. The latter will only be useful
398     // when we fix https://bugs.webkit.org/show_bug.cgi?id=23799, so I
399     // will leave the Euler angle code here for now.
400 
401     // ret.rotateY = asin(-row[0][2]);
402     // if (cos(ret.rotateY) != 0) {
403     //     ret.rotateX = atan2(row[1][2], row[2][2]);
404     //     ret.rotateZ = atan2(row[0][1], row[0][0]);
405     // } else {
406     //     ret.rotateX = atan2(-row[2][0], row[1][1]);
407     //     ret.rotateZ = 0;
408     // }
409 
410     double s, t, x, y, z, w;
411 
412     t = row[0][0] + row[1][1] + row[2][2] + 1.0;
413 
414     if (t > 1e-4) {
415         s = 0.5 / sqrt(t);
416         w = 0.25 / s;
417         x = (row[2][1] - row[1][2]) * s;
418         y = (row[0][2] - row[2][0]) * s;
419         z = (row[1][0] - row[0][1]) * s;
420     } else if (row[0][0] > row[1][1] && row[0][0] > row[2][2]) {
421         s = sqrt (1.0 + row[0][0] - row[1][1] - row[2][2]) * 2.0; // S=4*qx
422         x = 0.25 * s;
423         y = (row[0][1] + row[1][0]) / s;
424         z = (row[0][2] + row[2][0]) / s;
425         w = (row[2][1] - row[1][2]) / s;
426     } else if (row[1][1] > row[2][2]) {
427         s = sqrt (1.0 + row[1][1] - row[0][0] - row[2][2]) * 2.0; // S=4*qy
428         x = (row[0][1] + row[1][0]) / s;
429         y = 0.25 * s;
430         z = (row[1][2] + row[2][1]) / s;
431         w = (row[0][2] - row[2][0]) / s;
432     } else {
433         s = sqrt(1.0 + row[2][2] - row[0][0] - row[1][1]) * 2.0; // S=4*qz
434         x = (row[0][2] + row[2][0]) / s;
435         y = (row[1][2] + row[2][1]) / s;
436         z = 0.25 * s;
437         w = (row[1][0] - row[0][1]) / s;
438     }
439 
440     result.quaternionX = x;
441     result.quaternionY = y;
442     result.quaternionZ = z;
443     result.quaternionW = w;
444 
445     return true;
446 }
447 
448 // Perform a spherical linear interpolation between the two
449 // passed quaternions with 0 <= t <= 1
slerp(double qa[4],const double qb[4],double t)450 static void slerp(double qa[4], const double qb[4], double t)
451 {
452     double ax, ay, az, aw;
453     double bx, by, bz, bw;
454     double cx, cy, cz, cw;
455     double angle;
456     double th, invth, scale, invscale;
457 
458     ax = qa[0]; ay = qa[1]; az = qa[2]; aw = qa[3];
459     bx = qb[0]; by = qb[1]; bz = qb[2]; bw = qb[3];
460 
461     angle = ax * bx + ay * by + az * bz + aw * bw;
462 
463     if (angle < 0.0) {
464         ax = -ax; ay = -ay;
465         az = -az; aw = -aw;
466         angle = -angle;
467     }
468 
469     if (angle + 1.0 > .05) {
470         if (1.0 - angle >= .05) {
471             th = acos (angle);
472             invth = 1.0 / sin (th);
473             scale = sin (th * (1.0 - t)) * invth;
474             invscale = sin (th * t) * invth;
475         } else {
476             scale = 1.0 - t;
477             invscale = t;
478         }
479     } else {
480         bx = -ay;
481         by = ax;
482         bz = -aw;
483         bw = az;
484         scale = sin(piDouble * (.5 - t));
485         invscale = sin (piDouble * t);
486     }
487 
488     cx = ax * scale + bx * invscale;
489     cy = ay * scale + by * invscale;
490     cz = az * scale + bz * invscale;
491     cw = aw * scale + bw * invscale;
492 
493     qa[0] = cx; qa[1] = cy; qa[2] = cz; qa[3] = cw;
494 }
495 
496 // End of Supporting Math Functions
497 
scale(double s)498 TransformationMatrix& TransformationMatrix::scale(double s)
499 {
500     return scaleNonUniform(s, s);
501 }
502 
rotateFromVector(double x,double y)503 TransformationMatrix& TransformationMatrix::rotateFromVector(double x, double y)
504 {
505     return rotate(rad2deg(atan2(y, x)));
506 }
507 
flipX()508 TransformationMatrix& TransformationMatrix::flipX()
509 {
510     return scaleNonUniform(-1.0f, 1.0f);
511 }
512 
flipY()513 TransformationMatrix& TransformationMatrix::flipY()
514 {
515     return scaleNonUniform(1.0f, -1.0f);
516 }
517 
projectPoint(const FloatPoint & p) const518 FloatPoint TransformationMatrix::projectPoint(const FloatPoint& p) const
519 {
520     // This is basically raytracing. We have a point in the destination
521     // plane with z=0, and we cast a ray parallel to the z-axis from that
522     // point to find the z-position at which it intersects the z=0 plane
523     // with the transform applied. Once we have that point we apply the
524     // inverse transform to find the corresponding point in the source
525     // space.
526     //
527     // Given a plane with normal Pn, and a ray starting at point R0 and
528     // with direction defined by the vector Rd, we can find the
529     // intersection point as a distance d from R0 in units of Rd by:
530     //
531     // d = -dot (Pn', R0) / dot (Pn', Rd)
532 
533     double x = p.x();
534     double y = p.y();
535     double z = -(m13() * x + m23() * y + m43()) / m33();
536 
537     double outX = x * m11() + y * m21() + z * m31() + m41();
538     double outY = x * m12() + y * m22() + z * m32() + m42();
539 
540     double w = x * m14() + y * m24() + z * m34() + m44();
541     if (w != 1 && w != 0) {
542         outX /= w;
543         outY /= w;
544     }
545 
546     return FloatPoint(static_cast<float>(outX), static_cast<float>(outY));
547 }
548 
projectQuad(const FloatQuad & q) const549 FloatQuad TransformationMatrix::projectQuad(const FloatQuad& q) const
550 {
551     FloatQuad projectedQuad;
552     projectedQuad.setP1(projectPoint(q.p1()));
553     projectedQuad.setP2(projectPoint(q.p2()));
554     projectedQuad.setP3(projectPoint(q.p3()));
555     projectedQuad.setP4(projectPoint(q.p4()));
556     return projectedQuad;
557 }
558 
mapPoint(const FloatPoint & p) const559 FloatPoint TransformationMatrix::mapPoint(const FloatPoint& p) const
560 {
561     if (isIdentityOrTranslation())
562         return FloatPoint(p.x() + static_cast<float>(m_matrix[3][0]), p.y() + static_cast<float>(m_matrix[3][1]));
563 
564     double x, y;
565     multVecMatrix(p.x(), p.y(), x, y);
566     return FloatPoint(static_cast<float>(x), static_cast<float>(y));
567 }
568 
mapPoint(const FloatPoint3D & p) const569 FloatPoint3D TransformationMatrix::mapPoint(const FloatPoint3D& p) const
570 {
571     if (isIdentityOrTranslation())
572         return FloatPoint3D(p.x() + static_cast<float>(m_matrix[3][0]),
573                             p.y() + static_cast<float>(m_matrix[3][1]),
574                             p.z() + static_cast<float>(m_matrix[3][2]));
575 
576     double x, y, z;
577     multVecMatrix(p.x(), p.y(), p.z(), x, y, z);
578     return FloatPoint3D(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z));
579 }
580 
mapRect(const IntRect & rect) const581 IntRect TransformationMatrix::mapRect(const IntRect &rect) const
582 {
583     return enclosingIntRect(mapRect(FloatRect(rect)));
584 }
585 
mapRect(const FloatRect & r) const586 FloatRect TransformationMatrix::mapRect(const FloatRect& r) const
587 {
588     if (isIdentityOrTranslation()) {
589         FloatRect mappedRect(r);
590         mappedRect.move(static_cast<float>(m_matrix[3][0]), static_cast<float>(m_matrix[3][1]));
591         return mappedRect;
592     }
593 
594     FloatQuad resultQuad = mapQuad(FloatQuad(r));
595     return resultQuad.boundingBox();
596 }
597 
mapQuad(const FloatQuad & q) const598 FloatQuad TransformationMatrix::mapQuad(const FloatQuad& q) const
599 {
600     if (isIdentityOrTranslation()) {
601         FloatQuad mappedQuad(q);
602         mappedQuad.move(static_cast<float>(m_matrix[3][0]), static_cast<float>(m_matrix[3][1]));
603         return mappedQuad;
604     }
605 
606     FloatQuad result;
607     result.setP1(mapPoint(q.p1()));
608     result.setP2(mapPoint(q.p2()));
609     result.setP3(mapPoint(q.p3()));
610     result.setP4(mapPoint(q.p4()));
611     return result;
612 }
613 
scaleNonUniform(double sx,double sy)614 TransformationMatrix& TransformationMatrix::scaleNonUniform(double sx, double sy)
615 {
616     TransformationMatrix mat;
617     mat.m_matrix[0][0] = sx;
618     mat.m_matrix[1][1] = sy;
619 
620     multLeft(mat);
621     return *this;
622 }
623 
scale3d(double sx,double sy,double sz)624 TransformationMatrix& TransformationMatrix::scale3d(double sx, double sy, double sz)
625 {
626     TransformationMatrix mat;
627     mat.m_matrix[0][0] = sx;
628     mat.m_matrix[1][1] = sy;
629     mat.m_matrix[2][2] = sz;
630 
631     multLeft(mat);
632     return *this;
633 }
634 
rotate3d(double x,double y,double z,double angle)635 TransformationMatrix& TransformationMatrix::rotate3d(double x, double y, double z, double angle)
636 {
637     // angles are in degrees. Switch to radians
638     angle = deg2rad(angle);
639 
640     angle /= 2.0f;
641     double sinA = sin(angle);
642     double cosA = cos(angle);
643     double sinA2 = sinA * sinA;
644 
645     // normalize
646     double length = sqrt(x * x + y * y + z * z);
647     if (length == 0) {
648         // bad vector, just use something reasonable
649         x = 0;
650         y = 0;
651         z = 1;
652     } else if (length != 1) {
653         x /= length;
654         y /= length;
655         z /= length;
656     }
657 
658     TransformationMatrix mat;
659 
660     // optimize case where axis is along major axis
661     if (x == 1.0f && y == 0.0f && z == 0.0f) {
662         mat.m_matrix[0][0] = 1.0f;
663         mat.m_matrix[0][1] = 0.0f;
664         mat.m_matrix[0][2] = 0.0f;
665         mat.m_matrix[1][0] = 0.0f;
666         mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2;
667         mat.m_matrix[1][2] = 2.0f * sinA * cosA;
668         mat.m_matrix[2][0] = 0.0f;
669         mat.m_matrix[2][1] = -2.0f * sinA * cosA;
670         mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2;
671         mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
672         mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
673         mat.m_matrix[3][3] = 1.0f;
674     } else if (x == 0.0f && y == 1.0f && z == 0.0f) {
675         mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2;
676         mat.m_matrix[0][1] = 0.0f;
677         mat.m_matrix[0][2] = -2.0f * sinA * cosA;
678         mat.m_matrix[1][0] = 0.0f;
679         mat.m_matrix[1][1] = 1.0f;
680         mat.m_matrix[1][2] = 0.0f;
681         mat.m_matrix[2][0] = 2.0f * sinA * cosA;
682         mat.m_matrix[2][1] = 0.0f;
683         mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2;
684         mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
685         mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
686         mat.m_matrix[3][3] = 1.0f;
687     } else if (x == 0.0f && y == 0.0f && z == 1.0f) {
688         mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2;
689         mat.m_matrix[0][1] = 2.0f * sinA * cosA;
690         mat.m_matrix[0][2] = 0.0f;
691         mat.m_matrix[1][0] = -2.0f * sinA * cosA;
692         mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2;
693         mat.m_matrix[1][2] = 0.0f;
694         mat.m_matrix[2][0] = 0.0f;
695         mat.m_matrix[2][1] = 0.0f;
696         mat.m_matrix[2][2] = 1.0f;
697         mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
698         mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
699         mat.m_matrix[3][3] = 1.0f;
700     } else {
701         double x2 = x*x;
702         double y2 = y*y;
703         double z2 = z*z;
704 
705         mat.m_matrix[0][0] = 1.0f - 2.0f * (y2 + z2) * sinA2;
706         mat.m_matrix[0][1] = 2.0f * (x * y * sinA2 + z * sinA * cosA);
707         mat.m_matrix[0][2] = 2.0f * (x * z * sinA2 - y * sinA * cosA);
708         mat.m_matrix[1][0] = 2.0f * (y * x * sinA2 - z * sinA * cosA);
709         mat.m_matrix[1][1] = 1.0f - 2.0f * (z2 + x2) * sinA2;
710         mat.m_matrix[1][2] = 2.0f * (y * z * sinA2 + x * sinA * cosA);
711         mat.m_matrix[2][0] = 2.0f * (z * x * sinA2 + y * sinA * cosA);
712         mat.m_matrix[2][1] = 2.0f * (z * y * sinA2 - x * sinA * cosA);
713         mat.m_matrix[2][2] = 1.0f - 2.0f * (x2 + y2) * sinA2;
714         mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
715         mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
716         mat.m_matrix[3][3] = 1.0f;
717     }
718     multLeft(mat);
719     return *this;
720 }
721 
rotate3d(double rx,double ry,double rz)722 TransformationMatrix& TransformationMatrix::rotate3d(double rx, double ry, double rz)
723 {
724     // angles are in degrees. Switch to radians
725     rx = deg2rad(rx);
726     ry = deg2rad(ry);
727     rz = deg2rad(rz);
728 
729     TransformationMatrix mat;
730 
731     rz /= 2.0f;
732     double sinA = sin(rz);
733     double cosA = cos(rz);
734     double sinA2 = sinA * sinA;
735 
736     mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2;
737     mat.m_matrix[0][1] = 2.0f * sinA * cosA;
738     mat.m_matrix[0][2] = 0.0f;
739     mat.m_matrix[1][0] = -2.0f * sinA * cosA;
740     mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2;
741     mat.m_matrix[1][2] = 0.0f;
742     mat.m_matrix[2][0] = 0.0f;
743     mat.m_matrix[2][1] = 0.0f;
744     mat.m_matrix[2][2] = 1.0f;
745     mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
746     mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
747     mat.m_matrix[3][3] = 1.0f;
748 
749     TransformationMatrix rmat(mat);
750 
751     ry /= 2.0f;
752     sinA = sin(ry);
753     cosA = cos(ry);
754     sinA2 = sinA * sinA;
755 
756     mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2;
757     mat.m_matrix[0][1] = 0.0f;
758     mat.m_matrix[0][2] = -2.0f * sinA * cosA;
759     mat.m_matrix[1][0] = 0.0f;
760     mat.m_matrix[1][1] = 1.0f;
761     mat.m_matrix[1][2] = 0.0f;
762     mat.m_matrix[2][0] = 2.0f * sinA * cosA;
763     mat.m_matrix[2][1] = 0.0f;
764     mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2;
765     mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
766     mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
767     mat.m_matrix[3][3] = 1.0f;
768 
769     rmat.multLeft(mat);
770 
771     rx /= 2.0f;
772     sinA = sin(rx);
773     cosA = cos(rx);
774     sinA2 = sinA * sinA;
775 
776     mat.m_matrix[0][0] = 1.0f;
777     mat.m_matrix[0][1] = 0.0f;
778     mat.m_matrix[0][2] = 0.0f;
779     mat.m_matrix[1][0] = 0.0f;
780     mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2;
781     mat.m_matrix[1][2] = 2.0f * sinA * cosA;
782     mat.m_matrix[2][0] = 0.0f;
783     mat.m_matrix[2][1] = -2.0f * sinA * cosA;
784     mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2;
785     mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f;
786     mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f;
787     mat.m_matrix[3][3] = 1.0f;
788 
789     rmat.multLeft(mat);
790 
791     multLeft(rmat);
792     return *this;
793 }
794 
translate(double tx,double ty)795 TransformationMatrix& TransformationMatrix::translate(double tx, double ty)
796 {
797     m_matrix[3][0] += tx * m_matrix[0][0] + ty * m_matrix[1][0];
798     m_matrix[3][1] += tx * m_matrix[0][1] + ty * m_matrix[1][1];
799     m_matrix[3][2] += tx * m_matrix[0][2] + ty * m_matrix[1][2];
800     m_matrix[3][3] += tx * m_matrix[0][3] + ty * m_matrix[1][3];
801     return *this;
802 }
803 
translate3d(double tx,double ty,double tz)804 TransformationMatrix& TransformationMatrix::translate3d(double tx, double ty, double tz)
805 {
806     m_matrix[3][0] += tx * m_matrix[0][0] + ty * m_matrix[1][0] + tz * m_matrix[2][0];
807     m_matrix[3][1] += tx * m_matrix[0][1] + ty * m_matrix[1][1] + tz * m_matrix[2][1];
808     m_matrix[3][2] += tx * m_matrix[0][2] + ty * m_matrix[1][2] + tz * m_matrix[2][2];
809     m_matrix[3][3] += tx * m_matrix[0][3] + ty * m_matrix[1][3] + tz * m_matrix[2][3];
810     return *this;
811 }
812 
translateRight(double tx,double ty)813 TransformationMatrix& TransformationMatrix::translateRight(double tx, double ty)
814 {
815     if (tx != 0) {
816         m_matrix[0][0] +=  m_matrix[0][3] * tx;
817         m_matrix[1][0] +=  m_matrix[1][3] * tx;
818         m_matrix[2][0] +=  m_matrix[2][3] * tx;
819         m_matrix[3][0] +=  m_matrix[3][3] * tx;
820     }
821 
822     if (ty != 0) {
823         m_matrix[0][1] +=  m_matrix[0][3] * ty;
824         m_matrix[1][1] +=  m_matrix[1][3] * ty;
825         m_matrix[2][1] +=  m_matrix[2][3] * ty;
826         m_matrix[3][1] +=  m_matrix[3][3] * ty;
827     }
828 
829     return *this;
830 }
831 
translateRight3d(double tx,double ty,double tz)832 TransformationMatrix& TransformationMatrix::translateRight3d(double tx, double ty, double tz)
833 {
834     translateRight(tx, ty);
835     if (tz != 0) {
836         m_matrix[0][2] +=  m_matrix[0][3] * tz;
837         m_matrix[1][2] +=  m_matrix[1][3] * tz;
838         m_matrix[2][2] +=  m_matrix[2][3] * tz;
839         m_matrix[3][2] +=  m_matrix[3][3] * tz;
840     }
841 
842     return *this;
843 }
844 
skew(double sx,double sy)845 TransformationMatrix& TransformationMatrix::skew(double sx, double sy)
846 {
847     // angles are in degrees. Switch to radians
848     sx = deg2rad(sx);
849     sy = deg2rad(sy);
850 
851     TransformationMatrix mat;
852     mat.m_matrix[0][1] = tan(sy); // note that the y shear goes in the first row
853     mat.m_matrix[1][0] = tan(sx); // and the x shear in the second row
854 
855     multLeft(mat);
856     return *this;
857 }
858 
applyPerspective(double p)859 TransformationMatrix& TransformationMatrix::applyPerspective(double p)
860 {
861     TransformationMatrix mat;
862     if (p != 0)
863         mat.m_matrix[2][3] = -1/p;
864 
865     multLeft(mat);
866     return *this;
867 }
868 
rectToRect(const FloatRect & from,const FloatRect & to)869 TransformationMatrix TransformationMatrix::rectToRect(const FloatRect& from, const FloatRect& to)
870 {
871     ASSERT(!from.isEmpty());
872     return TransformationMatrix(to.width() / from.width(),
873                                 0, 0,
874                                 to.height() / from.height(),
875                                 to.x() - from.x(),
876                                 to.y() - from.y());
877 }
878 
879 //
880 // *this = mat * *this
881 //
multLeft(const TransformationMatrix & mat)882 TransformationMatrix& TransformationMatrix::multLeft(const TransformationMatrix& mat)
883 {
884     Matrix4 tmp;
885 
886     tmp[0][0] = (mat.m_matrix[0][0] * m_matrix[0][0] + mat.m_matrix[0][1] * m_matrix[1][0]
887                + mat.m_matrix[0][2] * m_matrix[2][0] + mat.m_matrix[0][3] * m_matrix[3][0]);
888     tmp[0][1] = (mat.m_matrix[0][0] * m_matrix[0][1] + mat.m_matrix[0][1] * m_matrix[1][1]
889                + mat.m_matrix[0][2] * m_matrix[2][1] + mat.m_matrix[0][3] * m_matrix[3][1]);
890     tmp[0][2] = (mat.m_matrix[0][0] * m_matrix[0][2] + mat.m_matrix[0][1] * m_matrix[1][2]
891                + mat.m_matrix[0][2] * m_matrix[2][2] + mat.m_matrix[0][3] * m_matrix[3][2]);
892     tmp[0][3] = (mat.m_matrix[0][0] * m_matrix[0][3] + mat.m_matrix[0][1] * m_matrix[1][3]
893                + mat.m_matrix[0][2] * m_matrix[2][3] + mat.m_matrix[0][3] * m_matrix[3][3]);
894 
895     tmp[1][0] = (mat.m_matrix[1][0] * m_matrix[0][0] + mat.m_matrix[1][1] * m_matrix[1][0]
896                + mat.m_matrix[1][2] * m_matrix[2][0] + mat.m_matrix[1][3] * m_matrix[3][0]);
897     tmp[1][1] = (mat.m_matrix[1][0] * m_matrix[0][1] + mat.m_matrix[1][1] * m_matrix[1][1]
898                + mat.m_matrix[1][2] * m_matrix[2][1] + mat.m_matrix[1][3] * m_matrix[3][1]);
899     tmp[1][2] = (mat.m_matrix[1][0] * m_matrix[0][2] + mat.m_matrix[1][1] * m_matrix[1][2]
900                + mat.m_matrix[1][2] * m_matrix[2][2] + mat.m_matrix[1][3] * m_matrix[3][2]);
901     tmp[1][3] = (mat.m_matrix[1][0] * m_matrix[0][3] + mat.m_matrix[1][1] * m_matrix[1][3]
902                + mat.m_matrix[1][2] * m_matrix[2][3] + mat.m_matrix[1][3] * m_matrix[3][3]);
903 
904     tmp[2][0] = (mat.m_matrix[2][0] * m_matrix[0][0] + mat.m_matrix[2][1] * m_matrix[1][0]
905                + mat.m_matrix[2][2] * m_matrix[2][0] + mat.m_matrix[2][3] * m_matrix[3][0]);
906     tmp[2][1] = (mat.m_matrix[2][0] * m_matrix[0][1] + mat.m_matrix[2][1] * m_matrix[1][1]
907                + mat.m_matrix[2][2] * m_matrix[2][1] + mat.m_matrix[2][3] * m_matrix[3][1]);
908     tmp[2][2] = (mat.m_matrix[2][0] * m_matrix[0][2] + mat.m_matrix[2][1] * m_matrix[1][2]
909                + mat.m_matrix[2][2] * m_matrix[2][2] + mat.m_matrix[2][3] * m_matrix[3][2]);
910     tmp[2][3] = (mat.m_matrix[2][0] * m_matrix[0][3] + mat.m_matrix[2][1] * m_matrix[1][3]
911                + mat.m_matrix[2][2] * m_matrix[2][3] + mat.m_matrix[2][3] * m_matrix[3][3]);
912 
913     tmp[3][0] = (mat.m_matrix[3][0] * m_matrix[0][0] + mat.m_matrix[3][1] * m_matrix[1][0]
914                + mat.m_matrix[3][2] * m_matrix[2][0] + mat.m_matrix[3][3] * m_matrix[3][0]);
915     tmp[3][1] = (mat.m_matrix[3][0] * m_matrix[0][1] + mat.m_matrix[3][1] * m_matrix[1][1]
916                + mat.m_matrix[3][2] * m_matrix[2][1] + mat.m_matrix[3][3] * m_matrix[3][1]);
917     tmp[3][2] = (mat.m_matrix[3][0] * m_matrix[0][2] + mat.m_matrix[3][1] * m_matrix[1][2]
918                + mat.m_matrix[3][2] * m_matrix[2][2] + mat.m_matrix[3][3] * m_matrix[3][2]);
919     tmp[3][3] = (mat.m_matrix[3][0] * m_matrix[0][3] + mat.m_matrix[3][1] * m_matrix[1][3]
920                + mat.m_matrix[3][2] * m_matrix[2][3] + mat.m_matrix[3][3] * m_matrix[3][3]);
921 
922     setMatrix(tmp);
923     return *this;
924 }
925 
multVecMatrix(double x,double y,double & resultX,double & resultY) const926 void TransformationMatrix::multVecMatrix(double x, double y, double& resultX, double& resultY) const
927 {
928     resultX = m_matrix[3][0] + x * m_matrix[0][0] + y * m_matrix[1][0];
929     resultY = m_matrix[3][1] + x * m_matrix[0][1] + y * m_matrix[1][1];
930     double w = m_matrix[3][3] + x * m_matrix[0][3] + y * m_matrix[1][3];
931     if (w != 1 && w != 0) {
932         resultX /= w;
933         resultY /= w;
934     }
935 }
936 
multVecMatrix(double x,double y,double z,double & resultX,double & resultY,double & resultZ) const937 void TransformationMatrix::multVecMatrix(double x, double y, double z, double& resultX, double& resultY, double& resultZ) const
938 {
939     resultX = m_matrix[3][0] + x * m_matrix[0][0] + y * m_matrix[1][0] + z * m_matrix[2][0];
940     resultY = m_matrix[3][1] + x * m_matrix[0][1] + y * m_matrix[1][1] + z * m_matrix[2][1];
941     resultZ = m_matrix[3][2] + x * m_matrix[0][2] + y * m_matrix[1][2] + z * m_matrix[2][2];
942     double w = m_matrix[3][3] + x * m_matrix[0][3] + y * m_matrix[1][3] + z * m_matrix[2][3];
943     if (w != 1 && w != 0) {
944         resultX /= w;
945         resultY /= w;
946         resultZ /= w;
947     }
948 }
949 
isInvertible() const950 bool TransformationMatrix::isInvertible() const
951 {
952     if (isIdentityOrTranslation())
953         return true;
954 
955     double det = WebCore::determinant4x4(m_matrix);
956 
957     if (fabs(det) < SMALL_NUMBER)
958         return false;
959 
960     return true;
961 }
962 
inverse() const963 TransformationMatrix TransformationMatrix::inverse() const
964 {
965     if (isIdentityOrTranslation()) {
966         // identity matrix
967         if (m_matrix[3][0] == 0 && m_matrix[3][1] == 0 && m_matrix[3][2] == 0)
968             return TransformationMatrix();
969 
970         // translation
971         return TransformationMatrix(1, 0, 0, 0,
972                                     0, 1, 0, 0,
973                                     0, 0, 1, 0,
974                                     -m_matrix[3][0], -m_matrix[3][1], -m_matrix[3][2], 1);
975     }
976 
977     TransformationMatrix invMat;
978     bool inverted = WebCore::inverse(m_matrix, invMat.m_matrix);
979     if (!inverted)
980         return TransformationMatrix();
981 
982     return invMat;
983 }
984 
makeAffine()985 void TransformationMatrix::makeAffine()
986 {
987     m_matrix[0][2] = 0;
988     m_matrix[0][3] = 0;
989 
990     m_matrix[1][2] = 0;
991     m_matrix[1][3] = 0;
992 
993     m_matrix[2][0] = 0;
994     m_matrix[2][1] = 0;
995     m_matrix[2][2] = 1;
996     m_matrix[2][3] = 0;
997 
998     m_matrix[3][2] = 0;
999     m_matrix[3][3] = 1;
1000 }
1001 
toAffineTransform() const1002 AffineTransform TransformationMatrix::toAffineTransform() const
1003 {
1004     return AffineTransform(m_matrix[0][0], m_matrix[0][1], m_matrix[1][0],
1005                            m_matrix[1][1], m_matrix[3][0], m_matrix[3][1]);
1006 }
1007 
blendFloat(double & from,double to,double progress)1008 static inline void blendFloat(double& from, double to, double progress)
1009 {
1010     if (from != to)
1011         from = from + (to - from) * progress;
1012 }
1013 
blend(const TransformationMatrix & from,double progress)1014 void TransformationMatrix::blend(const TransformationMatrix& from, double progress)
1015 {
1016     if (from.isIdentity() && isIdentity())
1017         return;
1018 
1019     // decompose
1020     DecomposedType fromDecomp;
1021     DecomposedType toDecomp;
1022     from.decompose(fromDecomp);
1023     decompose(toDecomp);
1024 
1025     // interpolate
1026     blendFloat(fromDecomp.scaleX, toDecomp.scaleX, progress);
1027     blendFloat(fromDecomp.scaleY, toDecomp.scaleY, progress);
1028     blendFloat(fromDecomp.scaleZ, toDecomp.scaleZ, progress);
1029     blendFloat(fromDecomp.skewXY, toDecomp.skewXY, progress);
1030     blendFloat(fromDecomp.skewXZ, toDecomp.skewXZ, progress);
1031     blendFloat(fromDecomp.skewYZ, toDecomp.skewYZ, progress);
1032     blendFloat(fromDecomp.translateX, toDecomp.translateX, progress);
1033     blendFloat(fromDecomp.translateY, toDecomp.translateY, progress);
1034     blendFloat(fromDecomp.translateZ, toDecomp.translateZ, progress);
1035     blendFloat(fromDecomp.perspectiveX, toDecomp.perspectiveX, progress);
1036     blendFloat(fromDecomp.perspectiveY, toDecomp.perspectiveY, progress);
1037     blendFloat(fromDecomp.perspectiveZ, toDecomp.perspectiveZ, progress);
1038     blendFloat(fromDecomp.perspectiveW, toDecomp.perspectiveW, progress);
1039 
1040     slerp(&fromDecomp.quaternionX, &toDecomp.quaternionX, progress);
1041 
1042     // recompose
1043     recompose(fromDecomp);
1044 }
1045 
decompose(DecomposedType & decomp) const1046 bool TransformationMatrix::decompose(DecomposedType& decomp) const
1047 {
1048     if (isIdentity()) {
1049         memset(&decomp, 0, sizeof(decomp));
1050         decomp.perspectiveW = 1;
1051         decomp.scaleX = 1;
1052         decomp.scaleY = 1;
1053         decomp.scaleZ = 1;
1054     }
1055 
1056     if (!WebCore::decompose(m_matrix, decomp))
1057         return false;
1058     return true;
1059 }
1060 
recompose(const DecomposedType & decomp)1061 void TransformationMatrix::recompose(const DecomposedType& decomp)
1062 {
1063     makeIdentity();
1064 
1065     // first apply perspective
1066     m_matrix[0][3] = (float) decomp.perspectiveX;
1067     m_matrix[1][3] = (float) decomp.perspectiveY;
1068     m_matrix[2][3] = (float) decomp.perspectiveZ;
1069     m_matrix[3][3] = (float) decomp.perspectiveW;
1070 
1071     // now translate
1072     translate3d((float) decomp.translateX, (float) decomp.translateY, (float) decomp.translateZ);
1073 
1074     // apply rotation
1075     double xx = decomp.quaternionX * decomp.quaternionX;
1076     double xy = decomp.quaternionX * decomp.quaternionY;
1077     double xz = decomp.quaternionX * decomp.quaternionZ;
1078     double xw = decomp.quaternionX * decomp.quaternionW;
1079     double yy = decomp.quaternionY * decomp.quaternionY;
1080     double yz = decomp.quaternionY * decomp.quaternionZ;
1081     double yw = decomp.quaternionY * decomp.quaternionW;
1082     double zz = decomp.quaternionZ * decomp.quaternionZ;
1083     double zw = decomp.quaternionZ * decomp.quaternionW;
1084 
1085     // Construct a composite rotation matrix from the quaternion values
1086     TransformationMatrix rotationMatrix(1 - 2 * (yy + zz), 2 * (xy - zw), 2 * (xz + yw), 0,
1087                            2 * (xy + zw), 1 - 2 * (xx + zz), 2 * (yz - xw), 0,
1088                            2 * (xz - yw), 2 * (yz + xw), 1 - 2 * (xx + yy), 0,
1089                            0, 0, 0, 1);
1090 
1091     multLeft(rotationMatrix);
1092 
1093     // now apply skew
1094     if (decomp.skewYZ) {
1095         TransformationMatrix tmp;
1096         tmp.setM32((float) decomp.skewYZ);
1097         multLeft(tmp);
1098     }
1099 
1100     if (decomp.skewXZ) {
1101         TransformationMatrix tmp;
1102         tmp.setM31((float) decomp.skewXZ);
1103         multLeft(tmp);
1104     }
1105 
1106     if (decomp.skewXY) {
1107         TransformationMatrix tmp;
1108         tmp.setM21((float) decomp.skewXY);
1109         multLeft(tmp);
1110     }
1111 
1112     // finally, apply scale
1113     scale3d((float) decomp.scaleX, (float) decomp.scaleY, (float) decomp.scaleZ);
1114 }
1115 
1116 }
1117