• 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  * Copyright (C) 2013 Google Inc. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include "config.h"
29 #include "platform/transforms/TransformationMatrix.h"
30 
31 #include "platform/geometry/FloatBox.h"
32 #include "platform/geometry/FloatQuad.h"
33 #include "platform/geometry/FloatRect.h"
34 #include "platform/geometry/IntRect.h"
35 #include "platform/geometry/LayoutRect.h"
36 #include "platform/transforms/AffineTransform.h"
37 
38 #include "wtf/Assertions.h"
39 #include "wtf/MathExtras.h"
40 
41 #if CPU(X86_64)
42 #include <emmintrin.h>
43 #endif
44 
45 namespace blink {
46 
47 //
48 // Supporting Math Functions
49 //
50 // This is a set of function from various places (attributed inline) to do things like
51 // inversion and decomposition of a 4x4 matrix. They are used throughout the code
52 //
53 
54 //
55 // Adapted from Matrix Inversion by Richard Carling, Graphics Gems <http://tog.acm.org/GraphicsGems/index.html>.
56 
57 // EULA: The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code
58 // as your own and resell it. Using the code is permitted in any program, product, or library, non-commercial
59 // or commercial. Giving credit is not required, though is a nice gesture. The code comes as-is, and if there
60 // are any flaws or problems with any Gems code, nobody involved with Gems - authors, editors, publishers, or
61 // webmasters - are to be held responsible. Basically, don't be a jerk, and remember that anything free comes
62 // with no guarantee.
63 
64 // A clarification about the storage of matrix elements
65 //
66 // This class uses a 2 dimensional array internally to store the elements of the matrix.  The first index into
67 // the array refers to the column that the element lies in; the second index refers to the row.
68 //
69 // In other words, this is the layout of the matrix:
70 //
71 // | m_matrix[0][0] m_matrix[1][0] m_matrix[2][0] m_matrix[3][0] |
72 // | m_matrix[0][1] m_matrix[1][1] m_matrix[2][1] m_matrix[3][1] |
73 // | m_matrix[0][2] m_matrix[1][2] m_matrix[2][2] m_matrix[3][2] |
74 // | m_matrix[0][3] m_matrix[1][3] m_matrix[2][3] m_matrix[3][3] |
75 
76 typedef double Vector4[4];
77 typedef double Vector3[3];
78 
79 const double SMALL_NUMBER = 1.e-8;
80 
81 // inverse(original_matrix, inverse_matrix)
82 //
83 // calculate the inverse of a 4x4 matrix
84 //
85 // -1
86 // A  = ___1__ adjoint A
87 //       det A
88 
89 //  double = determinant2x2(double a, double b, double c, double d)
90 //
91 //  calculate the determinant of a 2x2 matrix.
92 
determinant2x2(double a,double b,double c,double d)93 static double determinant2x2(double a, double b, double c, double d)
94 {
95     return a * d - b * c;
96 }
97 
98 //  double = determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3)
99 //
100 //  Calculate the determinant of a 3x3 matrix
101 //  in the form
102 //
103 //      | a1,  b1,  c1 |
104 //      | a2,  b2,  c2 |
105 //      | a3,  b3,  c3 |
106 
determinant3x3(double a1,double a2,double a3,double b1,double b2,double b3,double c1,double c2,double c3)107 static double determinant3x3(double a1, double a2, double a3, double b1, double b2, double b3, double c1, double c2, double c3)
108 {
109     return a1 * determinant2x2(b2, b3, c2, c3)
110          - b1 * determinant2x2(a2, a3, c2, c3)
111          + c1 * determinant2x2(a2, a3, b2, b3);
112 }
113 
114 //  double = determinant4x4(matrix)
115 //
116 //  calculate the determinant of a 4x4 matrix.
117 
determinant4x4(const TransformationMatrix::Matrix4 & m)118 static double determinant4x4(const TransformationMatrix::Matrix4& m)
119 {
120     // Assign to individual variable names to aid selecting
121     // correct elements
122 
123     double a1 = m[0][0];
124     double b1 = m[0][1];
125     double c1 = m[0][2];
126     double d1 = m[0][3];
127 
128     double a2 = m[1][0];
129     double b2 = m[1][1];
130     double c2 = m[1][2];
131     double d2 = m[1][3];
132 
133     double a3 = m[2][0];
134     double b3 = m[2][1];
135     double c3 = m[2][2];
136     double d3 = m[2][3];
137 
138     double a4 = m[3][0];
139     double b4 = m[3][1];
140     double c4 = m[3][2];
141     double d4 = m[3][3];
142 
143     return a1 * determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4)
144          - b1 * determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4)
145          + c1 * determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4)
146          - d1 * determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);
147 }
148 
149 // adjoint( original_matrix, inverse_matrix )
150 //
151 //   calculate the adjoint of a 4x4 matrix
152 //
153 //    Let  a   denote the minor determinant of matrix A obtained by
154 //         ij
155 //
156 //    deleting the ith row and jth column from A.
157 //
158 //                  i+j
159 //   Let  b   = (-1)    a
160 //        ij            ji
161 //
162 //  The matrix B = (b  ) is the adjoint of A
163 //                   ij
164 
adjoint(const TransformationMatrix::Matrix4 & matrix,TransformationMatrix::Matrix4 & result)165 static void adjoint(const TransformationMatrix::Matrix4& matrix, TransformationMatrix::Matrix4& result)
166 {
167     // Assign to individual variable names to aid
168     // selecting correct values
169     double a1 = matrix[0][0];
170     double b1 = matrix[0][1];
171     double c1 = matrix[0][2];
172     double d1 = matrix[0][3];
173 
174     double a2 = matrix[1][0];
175     double b2 = matrix[1][1];
176     double c2 = matrix[1][2];
177     double d2 = matrix[1][3];
178 
179     double a3 = matrix[2][0];
180     double b3 = matrix[2][1];
181     double c3 = matrix[2][2];
182     double d3 = matrix[2][3];
183 
184     double a4 = matrix[3][0];
185     double b4 = matrix[3][1];
186     double c4 = matrix[3][2];
187     double d4 = matrix[3][3];
188 
189     // Row column labeling reversed since we transpose rows & columns
190     result[0][0]  =   determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4);
191     result[1][0]  = - determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4);
192     result[2][0]  =   determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4);
193     result[3][0]  = - determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);
194 
195     result[0][1]  = - determinant3x3(b1, b3, b4, c1, c3, c4, d1, d3, d4);
196     result[1][1]  =   determinant3x3(a1, a3, a4, c1, c3, c4, d1, d3, d4);
197     result[2][1]  = - determinant3x3(a1, a3, a4, b1, b3, b4, d1, d3, d4);
198     result[3][1]  =   determinant3x3(a1, a3, a4, b1, b3, b4, c1, c3, c4);
199 
200     result[0][2]  =   determinant3x3(b1, b2, b4, c1, c2, c4, d1, d2, d4);
201     result[1][2]  = - determinant3x3(a1, a2, a4, c1, c2, c4, d1, d2, d4);
202     result[2][2]  =   determinant3x3(a1, a2, a4, b1, b2, b4, d1, d2, d4);
203     result[3][2]  = - determinant3x3(a1, a2, a4, b1, b2, b4, c1, c2, c4);
204 
205     result[0][3]  = - determinant3x3(b1, b2, b3, c1, c2, c3, d1, d2, d3);
206     result[1][3]  =   determinant3x3(a1, a2, a3, c1, c2, c3, d1, d2, d3);
207     result[2][3]  = - determinant3x3(a1, a2, a3, b1, b2, b3, d1, d2, d3);
208     result[3][3]  =   determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3);
209 }
210 
211 // Returns false if the matrix is not invertible
inverse(const TransformationMatrix::Matrix4 & matrix,TransformationMatrix::Matrix4 & result)212 static bool inverse(const TransformationMatrix::Matrix4& matrix, TransformationMatrix::Matrix4& result)
213 {
214     // Calculate the adjoint matrix
215     adjoint(matrix, result);
216 
217     // Calculate the 4x4 determinant
218     // If the determinant is zero,
219     // then the inverse matrix is not unique.
220     double det = determinant4x4(matrix);
221 
222     if (fabs(det) < SMALL_NUMBER)
223         return false;
224 
225     // Scale the adjoint matrix to get the inverse
226 
227     for (int i = 0; i < 4; i++)
228         for (int j = 0; j < 4; j++)
229             result[i][j] = result[i][j] / det;
230 
231     return true;
232 }
233 
234 // End of code adapted from Matrix Inversion by Richard Carling
235 
236 // Perform a decomposition on the passed matrix, return false if unsuccessful
237 // From Graphics Gems: unmatrix.c
238 
239 // Transpose rotation portion of matrix a, return b
transposeMatrix4(const TransformationMatrix::Matrix4 & a,TransformationMatrix::Matrix4 & b)240 static void transposeMatrix4(const TransformationMatrix::Matrix4& a, TransformationMatrix::Matrix4& b)
241 {
242     for (int i = 0; i < 4; i++)
243         for (int j = 0; j < 4; j++)
244             b[i][j] = a[j][i];
245 }
246 
247 // Multiply a homogeneous point by a matrix and return the transformed point
v4MulPointByMatrix(const Vector4 p,const TransformationMatrix::Matrix4 & m,Vector4 result)248 static void v4MulPointByMatrix(const Vector4 p, const TransformationMatrix::Matrix4& m, Vector4 result)
249 {
250     result[0] = (p[0] * m[0][0]) + (p[1] * m[1][0]) +
251                 (p[2] * m[2][0]) + (p[3] * m[3][0]);
252     result[1] = (p[0] * m[0][1]) + (p[1] * m[1][1]) +
253                 (p[2] * m[2][1]) + (p[3] * m[3][1]);
254     result[2] = (p[0] * m[0][2]) + (p[1] * m[1][2]) +
255                 (p[2] * m[2][2]) + (p[3] * m[3][2]);
256     result[3] = (p[0] * m[0][3]) + (p[1] * m[1][3]) +
257                 (p[2] * m[2][3]) + (p[3] * m[3][3]);
258 }
259 
v3Length(Vector3 a)260 static double v3Length(Vector3 a)
261 {
262     return std::sqrt((a[0] * a[0]) + (a[1] * a[1]) + (a[2] * a[2]));
263 }
264 
v3Scale(Vector3 v,double desiredLength)265 static void v3Scale(Vector3 v, double desiredLength)
266 {
267     double len = v3Length(v);
268     if (len != 0) {
269         double l = desiredLength / len;
270         v[0] *= l;
271         v[1] *= l;
272         v[2] *= l;
273     }
274 }
275 
v3Dot(const Vector3 a,const Vector3 b)276 static double v3Dot(const Vector3 a, const Vector3 b)
277 {
278     return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]);
279 }
280 
281 // Make a linear combination of two vectors and return the result.
282 // result = (a * ascl) + (b * bscl)
v3Combine(const Vector3 a,const Vector3 b,Vector3 result,double ascl,double bscl)283 static void v3Combine(const Vector3 a, const Vector3 b, Vector3 result, double ascl, double bscl)
284 {
285     result[0] = (ascl * a[0]) + (bscl * b[0]);
286     result[1] = (ascl * a[1]) + (bscl * b[1]);
287     result[2] = (ascl * a[2]) + (bscl * b[2]);
288 }
289 
290 // Return the cross product result = a cross b */
v3Cross(const Vector3 a,const Vector3 b,Vector3 result)291 static void v3Cross(const Vector3 a, const Vector3 b, Vector3 result)
292 {
293     result[0] = (a[1] * b[2]) - (a[2] * b[1]);
294     result[1] = (a[2] * b[0]) - (a[0] * b[2]);
295     result[2] = (a[0] * b[1]) - (a[1] * b[0]);
296 }
297 
decompose(const TransformationMatrix::Matrix4 & mat,TransformationMatrix::DecomposedType & result)298 static bool decompose(const TransformationMatrix::Matrix4& mat, TransformationMatrix::DecomposedType& result)
299 {
300     TransformationMatrix::Matrix4 localMatrix;
301     memcpy(localMatrix, mat, sizeof(TransformationMatrix::Matrix4));
302 
303     // Normalize the matrix.
304     if (localMatrix[3][3] == 0)
305         return false;
306 
307     int i, j;
308     for (i = 0; i < 4; i++)
309         for (j = 0; j < 4; j++)
310             localMatrix[i][j] /= localMatrix[3][3];
311 
312     // perspectiveMatrix is used to solve for perspective, but it also provides
313     // an easy way to test for singularity of the upper 3x3 component.
314     TransformationMatrix::Matrix4 perspectiveMatrix;
315     memcpy(perspectiveMatrix, localMatrix, sizeof(TransformationMatrix::Matrix4));
316     for (i = 0; i < 3; i++)
317         perspectiveMatrix[i][3] = 0;
318     perspectiveMatrix[3][3] = 1;
319 
320     if (determinant4x4(perspectiveMatrix) == 0)
321         return false;
322 
323     // First, isolate perspective.  This is the messiest.
324     if (localMatrix[0][3] != 0 || localMatrix[1][3] != 0 || localMatrix[2][3] != 0) {
325         // rightHandSide is the right hand side of the equation.
326         Vector4 rightHandSide;
327         rightHandSide[0] = localMatrix[0][3];
328         rightHandSide[1] = localMatrix[1][3];
329         rightHandSide[2] = localMatrix[2][3];
330         rightHandSide[3] = localMatrix[3][3];
331 
332         // Solve the equation by inverting perspectiveMatrix and multiplying
333         // rightHandSide by the inverse.  (This is the easiest way, not
334         // necessarily the best.)
335         TransformationMatrix::Matrix4 inversePerspectiveMatrix, transposedInversePerspectiveMatrix;
336         inverse(perspectiveMatrix, inversePerspectiveMatrix);
337         transposeMatrix4(inversePerspectiveMatrix, transposedInversePerspectiveMatrix);
338 
339         Vector4 perspectivePoint;
340         v4MulPointByMatrix(rightHandSide, transposedInversePerspectiveMatrix, perspectivePoint);
341 
342         result.perspectiveX = perspectivePoint[0];
343         result.perspectiveY = perspectivePoint[1];
344         result.perspectiveZ = perspectivePoint[2];
345         result.perspectiveW = perspectivePoint[3];
346 
347         // Clear the perspective partition
348         localMatrix[0][3] = localMatrix[1][3] = localMatrix[2][3] = 0;
349         localMatrix[3][3] = 1;
350     } else {
351         // No perspective.
352         result.perspectiveX = result.perspectiveY = result.perspectiveZ = 0;
353         result.perspectiveW = 1;
354     }
355 
356     // Next take care of translation (easy).
357     result.translateX = localMatrix[3][0];
358     localMatrix[3][0] = 0;
359     result.translateY = localMatrix[3][1];
360     localMatrix[3][1] = 0;
361     result.translateZ = localMatrix[3][2];
362     localMatrix[3][2] = 0;
363 
364     // Vector4 type and functions need to be added to the common set.
365     Vector3 row[3], pdum3;
366 
367     // Now get scale and shear.
368     for (i = 0; i < 3; i++) {
369         row[i][0] = localMatrix[i][0];
370         row[i][1] = localMatrix[i][1];
371         row[i][2] = localMatrix[i][2];
372     }
373 
374     // Compute X scale factor and normalize first row.
375     result.scaleX = v3Length(row[0]);
376     v3Scale(row[0], 1.0);
377 
378     // Compute XY shear factor and make 2nd row orthogonal to 1st.
379     result.skewXY = v3Dot(row[0], row[1]);
380     v3Combine(row[1], row[0], row[1], 1.0, -result.skewXY);
381 
382     // Now, compute Y scale and normalize 2nd row.
383     result.scaleY = v3Length(row[1]);
384     v3Scale(row[1], 1.0);
385     result.skewXY /= result.scaleY;
386 
387     // Compute XZ and YZ shears, orthogonalize 3rd row.
388     result.skewXZ = v3Dot(row[0], row[2]);
389     v3Combine(row[2], row[0], row[2], 1.0, -result.skewXZ);
390     result.skewYZ = v3Dot(row[1], row[2]);
391     v3Combine(row[2], row[1], row[2], 1.0, -result.skewYZ);
392 
393     // Next, get Z scale and normalize 3rd row.
394     result.scaleZ = v3Length(row[2]);
395     v3Scale(row[2], 1.0);
396     result.skewXZ /= result.scaleZ;
397     result.skewYZ /= result.scaleZ;
398 
399     // At this point, the matrix (in rows[]) is orthonormal.
400     // Check for a coordinate system flip.  If the determinant
401     // is -1, then negate the matrix and the scaling factors.
402     v3Cross(row[1], row[2], pdum3);
403     if (v3Dot(row[0], pdum3) < 0) {
404 
405         result.scaleX *= -1;
406         result.scaleY *= -1;
407         result.scaleZ *= -1;
408 
409         for (i = 0; i < 3; i++) {
410             row[i][0] *= -1;
411             row[i][1] *= -1;
412             row[i][2] *= -1;
413         }
414     }
415 
416     // Now, get the rotations out, as described in the gem.
417 
418     // FIXME - Add the ability to return either quaternions (which are
419     // easier to recompose with) or Euler angles (rx, ry, rz), which
420     // are easier for authors to deal with. The latter will only be useful
421     // when we fix https://bugs.webkit.org/show_bug.cgi?id=23799, so I
422     // will leave the Euler angle code here for now.
423 
424     // ret.rotateY = asin(-row[0][2]);
425     // if (cos(ret.rotateY) != 0) {
426     //     ret.rotateX = atan2(row[1][2], row[2][2]);
427     //     ret.rotateZ = atan2(row[0][1], row[0][0]);
428     // } else {
429     //     ret.rotateX = atan2(-row[2][0], row[1][1]);
430     //     ret.rotateZ = 0;
431     // }
432 
433     double s, t, x, y, z, w;
434 
435     t = row[0][0] + row[1][1] + row[2][2] + 1.0;
436 
437     if (t > 1e-4) {
438         s = 0.5 / std::sqrt(t);
439         w = 0.25 / s;
440         x = (row[2][1] - row[1][2]) * s;
441         y = (row[0][2] - row[2][0]) * s;
442         z = (row[1][0] - row[0][1]) * s;
443     } else if (row[0][0] > row[1][1] && row[0][0] > row[2][2]) {
444         s = std::sqrt(1.0 + row[0][0] - row[1][1] - row[2][2]) * 2.0; // S=4*qx
445         x = 0.25 * s;
446         y = (row[0][1] + row[1][0]) / s;
447         z = (row[0][2] + row[2][0]) / s;
448         w = (row[2][1] - row[1][2]) / s;
449     } else if (row[1][1] > row[2][2]) {
450         s = std::sqrt(1.0 + row[1][1] - row[0][0] - row[2][2]) * 2.0; // S=4*qy
451         x = (row[0][1] + row[1][0]) / s;
452         y = 0.25 * s;
453         z = (row[1][2] + row[2][1]) / s;
454         w = (row[0][2] - row[2][0]) / s;
455     } else {
456         s = std::sqrt(1.0 + row[2][2] - row[0][0] - row[1][1]) * 2.0; // S=4*qz
457         x = (row[0][2] + row[2][0]) / s;
458         y = (row[1][2] + row[2][1]) / s;
459         z = 0.25 * s;
460         w = (row[1][0] - row[0][1]) / s;
461     }
462 
463     result.quaternionX = x;
464     result.quaternionY = y;
465     result.quaternionZ = z;
466     result.quaternionW = w;
467 
468     return true;
469 }
470 
471 // Perform a spherical linear interpolation between the two
472 // passed quaternions with 0 <= t <= 1
slerp(double qa[4],const double qb[4],double t)473 static void slerp(double qa[4], const double qb[4], double t)
474 {
475     double ax, ay, az, aw;
476     double bx, by, bz, bw;
477     double cx, cy, cz, cw;
478     double angle;
479     double th, invth, scale, invscale;
480 
481     ax = qa[0]; ay = qa[1]; az = qa[2]; aw = qa[3];
482     bx = qb[0]; by = qb[1]; bz = qb[2]; bw = qb[3];
483 
484     angle = ax * bx + ay * by + az * bz + aw * bw;
485 
486     if (angle < 0.0) {
487         ax = -ax; ay = -ay;
488         az = -az; aw = -aw;
489         angle = -angle;
490     }
491 
492     if (angle + 1.0 > .05) {
493         if (1.0 - angle >= .05) {
494             th = std::acos(angle);
495             invth = 1.0 / std::sin(th);
496             scale = std::sin(th * (1.0 - t)) * invth;
497             invscale = std::sin(th * t) * invth;
498         } else {
499             scale = 1.0 - t;
500             invscale = t;
501         }
502     } else {
503         bx = -ay;
504         by = ax;
505         bz = -aw;
506         bw = az;
507         scale = std::sin(piDouble * (.5 - t));
508         invscale = std::sin(piDouble * t);
509     }
510 
511     cx = ax * scale + bx * invscale;
512     cy = ay * scale + by * invscale;
513     cz = az * scale + bz * invscale;
514     cw = aw * scale + bw * invscale;
515 
516     qa[0] = cx; qa[1] = cy; qa[2] = cz; qa[3] = cw;
517 }
518 
519 // End of Supporting Math Functions
520 
TransformationMatrix(const AffineTransform & t)521 TransformationMatrix::TransformationMatrix(const AffineTransform& t)
522 {
523     setMatrix(t.a(), t.b(), t.c(), t.d(), t.e(), t.f());
524 }
525 
scale(double s)526 TransformationMatrix& TransformationMatrix::scale(double s)
527 {
528     return scaleNonUniform(s, s);
529 }
530 
rotateFromVector(double x,double y)531 TransformationMatrix& TransformationMatrix::rotateFromVector(double x, double y)
532 {
533     return rotate(rad2deg(atan2(y, x)));
534 }
535 
flipX()536 TransformationMatrix& TransformationMatrix::flipX()
537 {
538     return scaleNonUniform(-1.0, 1.0);
539 }
540 
flipY()541 TransformationMatrix& TransformationMatrix::flipY()
542 {
543     return scaleNonUniform(1.0, -1.0);
544 }
545 
projectPoint(const FloatPoint & p,bool * clamped) const546 FloatPoint TransformationMatrix::projectPoint(const FloatPoint& p, bool* clamped) const
547 {
548     // This is basically raytracing. We have a point in the destination
549     // plane with z=0, and we cast a ray parallel to the z-axis from that
550     // point to find the z-position at which it intersects the z=0 plane
551     // with the transform applied. Once we have that point we apply the
552     // inverse transform to find the corresponding point in the source
553     // space.
554     //
555     // Given a plane with normal Pn, and a ray starting at point R0 and
556     // with direction defined by the vector Rd, we can find the
557     // intersection point as a distance d from R0 in units of Rd by:
558     //
559     // d = -dot (Pn', R0) / dot (Pn', Rd)
560     if (clamped)
561         *clamped = false;
562 
563     if (m33() == 0) {
564         // In this case, the projection plane is parallel to the ray we are trying to
565         // trace, and there is no well-defined value for the projection.
566         return FloatPoint();
567     }
568 
569     double x = p.x();
570     double y = p.y();
571     double z = -(m13() * x + m23() * y + m43()) / m33();
572 
573     // FIXME: use multVecMatrix()
574     double outX = x * m11() + y * m21() + z * m31() + m41();
575     double outY = x * m12() + y * m22() + z * m32() + m42();
576 
577     double w = x * m14() + y * m24() + z * m34() + m44();
578     if (w <= 0) {
579         // Using int max causes overflow when other code uses the projected point. To
580         // represent infinity yet reduce the risk of overflow, we use a large but
581         // not-too-large number here when clamping.
582         const int largeNumber = 100000000 / kFixedPointDenominator;
583         outX = copysign(largeNumber, outX);
584         outY = copysign(largeNumber, outY);
585         if (clamped)
586             *clamped = true;
587     } else if (w != 1) {
588         outX /= w;
589         outY /= w;
590     }
591 
592     return FloatPoint(static_cast<float>(outX), static_cast<float>(outY));
593 }
594 
projectQuad(const FloatQuad & q,bool * clamped) const595 FloatQuad TransformationMatrix::projectQuad(const FloatQuad& q, bool* clamped) const
596 {
597     FloatQuad projectedQuad;
598 
599     bool clamped1 = false;
600     bool clamped2 = false;
601     bool clamped3 = false;
602     bool clamped4 = false;
603 
604     projectedQuad.setP1(projectPoint(q.p1(), &clamped1));
605     projectedQuad.setP2(projectPoint(q.p2(), &clamped2));
606     projectedQuad.setP3(projectPoint(q.p3(), &clamped3));
607     projectedQuad.setP4(projectPoint(q.p4(), &clamped4));
608 
609     if (clamped)
610         *clamped = clamped1 || clamped2 || clamped3 || clamped4;
611 
612     // If all points on the quad had w < 0, then the entire quad would not be visible to the projected surface.
613     bool everythingWasClipped = clamped1 && clamped2 && clamped3 && clamped4;
614     if (everythingWasClipped)
615         return FloatQuad();
616 
617     return projectedQuad;
618 }
619 
clampEdgeValue(float f)620 static float clampEdgeValue(float f)
621 {
622     ASSERT(!std::isnan(f));
623     return std::min<float>(std::max<float>(f, (-LayoutUnit::max() / 2).toFloat()), (LayoutUnit::max() / 2).toFloat());
624 }
625 
clampedBoundsOfProjectedQuad(const FloatQuad & q) const626 LayoutRect TransformationMatrix::clampedBoundsOfProjectedQuad(const FloatQuad& q) const
627 {
628     FloatRect mappedQuadBounds = projectQuad(q).boundingBox();
629 
630     float left = clampEdgeValue(floorf(mappedQuadBounds.x()));
631     float top = clampEdgeValue(floorf(mappedQuadBounds.y()));
632 
633     float right;
634     if (std::isinf(mappedQuadBounds.x()) && std::isinf(mappedQuadBounds.width()))
635         right = (LayoutUnit::max() / 2).toFloat();
636     else
637         right = clampEdgeValue(ceilf(mappedQuadBounds.maxX()));
638 
639     float bottom;
640     if (std::isinf(mappedQuadBounds.y()) && std::isinf(mappedQuadBounds.height()))
641         bottom = (LayoutUnit::max() / 2).toFloat();
642     else
643         bottom = clampEdgeValue(ceilf(mappedQuadBounds.maxY()));
644 
645     return LayoutRect(LayoutUnit::clamp(left), LayoutUnit::clamp(top),  LayoutUnit::clamp(right - left), LayoutUnit::clamp(bottom - top));
646 }
647 
transformBox(FloatBox & box) const648 void TransformationMatrix::transformBox(FloatBox& box) const
649 {
650     FloatBox bounds;
651     bool firstPoint = true;
652     for (size_t i = 0; i < 2; ++i) {
653         for (size_t j = 0; j < 2; ++j) {
654             for (size_t k = 0; k < 2; ++k) {
655                 FloatPoint3D point(box.x(), box.y(), box.z());
656                 point += FloatPoint3D(i * box.width(), j * box.height(), k * box.depth());
657                 point = mapPoint(point);
658                 if (firstPoint) {
659                     bounds.setOrigin(point);
660                     firstPoint = false;
661                 } else {
662                     bounds.expandTo(point);
663                 }
664             }
665         }
666     }
667     box = bounds;
668 }
669 
mapPoint(const FloatPoint & p) const670 FloatPoint TransformationMatrix::mapPoint(const FloatPoint& p) const
671 {
672     if (isIdentityOrTranslation())
673         return FloatPoint(p.x() + static_cast<float>(m_matrix[3][0]), p.y() + static_cast<float>(m_matrix[3][1]));
674 
675     return internalMapPoint(p);
676 }
677 
mapPoint(const FloatPoint3D & p) const678 FloatPoint3D TransformationMatrix::mapPoint(const FloatPoint3D& p) const
679 {
680     if (isIdentityOrTranslation())
681         return FloatPoint3D(p.x() + static_cast<float>(m_matrix[3][0]),
682                             p.y() + static_cast<float>(m_matrix[3][1]),
683                             p.z() + static_cast<float>(m_matrix[3][2]));
684 
685     return internalMapPoint(p);
686 }
687 
mapRect(const IntRect & rect) const688 IntRect TransformationMatrix::mapRect(const IntRect &rect) const
689 {
690     return enclosingIntRect(mapRect(FloatRect(rect)));
691 }
692 
mapRect(const LayoutRect & r) const693 LayoutRect TransformationMatrix::mapRect(const LayoutRect& r) const
694 {
695     return enclosingLayoutRect(mapRect(FloatRect(r)));
696 }
697 
mapRect(const FloatRect & r) const698 FloatRect TransformationMatrix::mapRect(const FloatRect& r) const
699 {
700     if (isIdentityOrTranslation()) {
701         FloatRect mappedRect(r);
702         mappedRect.move(static_cast<float>(m_matrix[3][0]), static_cast<float>(m_matrix[3][1]));
703         return mappedRect;
704     }
705 
706     FloatQuad result;
707 
708     float maxX = r.maxX();
709     float maxY = r.maxY();
710     result.setP1(internalMapPoint(FloatPoint(r.x(), r.y())));
711     result.setP2(internalMapPoint(FloatPoint(maxX, r.y())));
712     result.setP3(internalMapPoint(FloatPoint(maxX, maxY)));
713     result.setP4(internalMapPoint(FloatPoint(r.x(), maxY)));
714 
715     return result.boundingBox();
716 }
717 
mapQuad(const FloatQuad & q) const718 FloatQuad TransformationMatrix::mapQuad(const FloatQuad& q) const
719 {
720     if (isIdentityOrTranslation()) {
721         FloatQuad mappedQuad(q);
722         mappedQuad.move(static_cast<float>(m_matrix[3][0]), static_cast<float>(m_matrix[3][1]));
723         return mappedQuad;
724     }
725 
726     FloatQuad result;
727     result.setP1(internalMapPoint(q.p1()));
728     result.setP2(internalMapPoint(q.p2()));
729     result.setP3(internalMapPoint(q.p3()));
730     result.setP4(internalMapPoint(q.p4()));
731     return result;
732 }
733 
scaleNonUniform(double sx,double sy)734 TransformationMatrix& TransformationMatrix::scaleNonUniform(double sx, double sy)
735 {
736     m_matrix[0][0] *= sx;
737     m_matrix[0][1] *= sx;
738     m_matrix[0][2] *= sx;
739     m_matrix[0][3] *= sx;
740 
741     m_matrix[1][0] *= sy;
742     m_matrix[1][1] *= sy;
743     m_matrix[1][2] *= sy;
744     m_matrix[1][3] *= sy;
745     return *this;
746 }
747 
scale3d(double sx,double sy,double sz)748 TransformationMatrix& TransformationMatrix::scale3d(double sx, double sy, double sz)
749 {
750     scaleNonUniform(sx, sy);
751 
752     m_matrix[2][0] *= sz;
753     m_matrix[2][1] *= sz;
754     m_matrix[2][2] *= sz;
755     m_matrix[2][3] *= sz;
756     return *this;
757 }
758 
rotate3d(double x,double y,double z,double angle)759 TransformationMatrix& TransformationMatrix::rotate3d(double x, double y, double z, double angle)
760 {
761     // Normalize the axis of rotation
762     double length = std::sqrt(x * x + y * y + z * z);
763     if (length == 0) {
764         // A direction vector that cannot be normalized, such as [0, 0, 0], will cause the rotation to not be applied.
765         return *this;
766     } else if (length != 1) {
767         x /= length;
768         y /= length;
769         z /= length;
770     }
771 
772     // Angles are in degrees. Switch to radians.
773     angle = deg2rad(angle);
774 
775     double sinTheta = std::sin(angle);
776     double cosTheta = std::cos(angle);
777 
778     TransformationMatrix mat;
779 
780     // Optimize cases where the axis is along a major axis
781     if (x == 1.0 && y == 0.0 && z == 0.0) {
782         mat.m_matrix[0][0] = 1.0;
783         mat.m_matrix[0][1] = 0.0;
784         mat.m_matrix[0][2] = 0.0;
785         mat.m_matrix[1][0] = 0.0;
786         mat.m_matrix[1][1] = cosTheta;
787         mat.m_matrix[1][2] = sinTheta;
788         mat.m_matrix[2][0] = 0.0;
789         mat.m_matrix[2][1] = -sinTheta;
790         mat.m_matrix[2][2] = cosTheta;
791         mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0;
792         mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0;
793         mat.m_matrix[3][3] = 1.0;
794     } else if (x == 0.0 && y == 1.0 && z == 0.0) {
795         mat.m_matrix[0][0] = cosTheta;
796         mat.m_matrix[0][1] = 0.0;
797         mat.m_matrix[0][2] = -sinTheta;
798         mat.m_matrix[1][0] = 0.0;
799         mat.m_matrix[1][1] = 1.0;
800         mat.m_matrix[1][2] = 0.0;
801         mat.m_matrix[2][0] = sinTheta;
802         mat.m_matrix[2][1] = 0.0;
803         mat.m_matrix[2][2] = cosTheta;
804         mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0;
805         mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0;
806         mat.m_matrix[3][3] = 1.0;
807     } else if (x == 0.0 && y == 0.0 && z == 1.0) {
808         mat.m_matrix[0][0] = cosTheta;
809         mat.m_matrix[0][1] = sinTheta;
810         mat.m_matrix[0][2] = 0.0;
811         mat.m_matrix[1][0] = -sinTheta;
812         mat.m_matrix[1][1] = cosTheta;
813         mat.m_matrix[1][2] = 0.0;
814         mat.m_matrix[2][0] = 0.0;
815         mat.m_matrix[2][1] = 0.0;
816         mat.m_matrix[2][2] = 1.0;
817         mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0;
818         mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0;
819         mat.m_matrix[3][3] = 1.0;
820     } else {
821         // This case is the rotation about an arbitrary unit vector.
822         //
823         // Formula is adapted from Wikipedia article on Rotation matrix,
824         // http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle
825         //
826         // An alternate resource with the same matrix: http://www.fastgraph.com/makegames/3drotation/
827         //
828         double oneMinusCosTheta = 1 - cosTheta;
829         mat.m_matrix[0][0] = cosTheta + x * x * oneMinusCosTheta;
830         mat.m_matrix[0][1] = y * x * oneMinusCosTheta + z * sinTheta;
831         mat.m_matrix[0][2] = z * x * oneMinusCosTheta - y * sinTheta;
832         mat.m_matrix[1][0] = x * y * oneMinusCosTheta - z * sinTheta;
833         mat.m_matrix[1][1] = cosTheta + y * y * oneMinusCosTheta;
834         mat.m_matrix[1][2] = z * y * oneMinusCosTheta + x * sinTheta;
835         mat.m_matrix[2][0] = x * z * oneMinusCosTheta + y * sinTheta;
836         mat.m_matrix[2][1] = y * z * oneMinusCosTheta - x * sinTheta;
837         mat.m_matrix[2][2] = cosTheta + z * z * oneMinusCosTheta;
838         mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0;
839         mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0;
840         mat.m_matrix[3][3] = 1.0;
841     }
842     multiply(mat);
843     return *this;
844 }
845 
rotate3d(double rx,double ry,double rz)846 TransformationMatrix& TransformationMatrix::rotate3d(double rx, double ry, double rz)
847 {
848     // Angles are in degrees. Switch to radians.
849     rx = deg2rad(rx);
850     ry = deg2rad(ry);
851     rz = deg2rad(rz);
852 
853     TransformationMatrix mat;
854 
855     double sinTheta = std::sin(rz);
856     double cosTheta = std::cos(rz);
857 
858     mat.m_matrix[0][0] = cosTheta;
859     mat.m_matrix[0][1] = sinTheta;
860     mat.m_matrix[0][2] = 0.0;
861     mat.m_matrix[1][0] = -sinTheta;
862     mat.m_matrix[1][1] = cosTheta;
863     mat.m_matrix[1][2] = 0.0;
864     mat.m_matrix[2][0] = 0.0;
865     mat.m_matrix[2][1] = 0.0;
866     mat.m_matrix[2][2] = 1.0;
867     mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0;
868     mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0;
869     mat.m_matrix[3][3] = 1.0;
870 
871     TransformationMatrix rmat(mat);
872 
873     sinTheta = std::sin(ry);
874     cosTheta = std::cos(ry);
875 
876     mat.m_matrix[0][0] = cosTheta;
877     mat.m_matrix[0][1] = 0.0;
878     mat.m_matrix[0][2] = -sinTheta;
879     mat.m_matrix[1][0] = 0.0;
880     mat.m_matrix[1][1] = 1.0;
881     mat.m_matrix[1][2] = 0.0;
882     mat.m_matrix[2][0] = sinTheta;
883     mat.m_matrix[2][1] = 0.0;
884     mat.m_matrix[2][2] = cosTheta;
885     mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0;
886     mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0;
887     mat.m_matrix[3][3] = 1.0;
888 
889     rmat.multiply(mat);
890 
891     sinTheta = std::sin(rx);
892     cosTheta = std::cos(rx);
893 
894     mat.m_matrix[0][0] = 1.0;
895     mat.m_matrix[0][1] = 0.0;
896     mat.m_matrix[0][2] = 0.0;
897     mat.m_matrix[1][0] = 0.0;
898     mat.m_matrix[1][1] = cosTheta;
899     mat.m_matrix[1][2] = sinTheta;
900     mat.m_matrix[2][0] = 0.0;
901     mat.m_matrix[2][1] = -sinTheta;
902     mat.m_matrix[2][2] = cosTheta;
903     mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0;
904     mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0;
905     mat.m_matrix[3][3] = 1.0;
906 
907     rmat.multiply(mat);
908 
909     multiply(rmat);
910     return *this;
911 }
912 
translate(double tx,double ty)913 TransformationMatrix& TransformationMatrix::translate(double tx, double ty)
914 {
915     m_matrix[3][0] += tx * m_matrix[0][0] + ty * m_matrix[1][0];
916     m_matrix[3][1] += tx * m_matrix[0][1] + ty * m_matrix[1][1];
917     m_matrix[3][2] += tx * m_matrix[0][2] + ty * m_matrix[1][2];
918     m_matrix[3][3] += tx * m_matrix[0][3] + ty * m_matrix[1][3];
919     return *this;
920 }
921 
translate3d(double tx,double ty,double tz)922 TransformationMatrix& TransformationMatrix::translate3d(double tx, double ty, double tz)
923 {
924     m_matrix[3][0] += tx * m_matrix[0][0] + ty * m_matrix[1][0] + tz * m_matrix[2][0];
925     m_matrix[3][1] += tx * m_matrix[0][1] + ty * m_matrix[1][1] + tz * m_matrix[2][1];
926     m_matrix[3][2] += tx * m_matrix[0][2] + ty * m_matrix[1][2] + tz * m_matrix[2][2];
927     m_matrix[3][3] += tx * m_matrix[0][3] + ty * m_matrix[1][3] + tz * m_matrix[2][3];
928     return *this;
929 }
930 
translateRight(double tx,double ty)931 TransformationMatrix& TransformationMatrix::translateRight(double tx, double ty)
932 {
933     if (tx != 0) {
934         m_matrix[0][0] +=  m_matrix[0][3] * tx;
935         m_matrix[1][0] +=  m_matrix[1][3] * tx;
936         m_matrix[2][0] +=  m_matrix[2][3] * tx;
937         m_matrix[3][0] +=  m_matrix[3][3] * tx;
938     }
939 
940     if (ty != 0) {
941         m_matrix[0][1] +=  m_matrix[0][3] * ty;
942         m_matrix[1][1] +=  m_matrix[1][3] * ty;
943         m_matrix[2][1] +=  m_matrix[2][3] * ty;
944         m_matrix[3][1] +=  m_matrix[3][3] * ty;
945     }
946 
947     return *this;
948 }
949 
translateRight3d(double tx,double ty,double tz)950 TransformationMatrix& TransformationMatrix::translateRight3d(double tx, double ty, double tz)
951 {
952     translateRight(tx, ty);
953     if (tz != 0) {
954         m_matrix[0][2] +=  m_matrix[0][3] * tz;
955         m_matrix[1][2] +=  m_matrix[1][3] * tz;
956         m_matrix[2][2] +=  m_matrix[2][3] * tz;
957         m_matrix[3][2] +=  m_matrix[3][3] * tz;
958     }
959 
960     return *this;
961 }
962 
skew(double sx,double sy)963 TransformationMatrix& TransformationMatrix::skew(double sx, double sy)
964 {
965     // angles are in degrees. Switch to radians
966     sx = deg2rad(sx);
967     sy = deg2rad(sy);
968 
969     TransformationMatrix mat;
970     mat.m_matrix[0][1] = std::tan(sy); // note that the y shear goes in the first row
971     mat.m_matrix[1][0] = std::tan(sx); // and the x shear in the second row
972 
973     multiply(mat);
974     return *this;
975 }
976 
applyPerspective(double p)977 TransformationMatrix& TransformationMatrix::applyPerspective(double p)
978 {
979     TransformationMatrix mat;
980     if (p != 0)
981         mat.m_matrix[2][3] = -1/p;
982 
983     multiply(mat);
984     return *this;
985 }
986 
rectToRect(const FloatRect & from,const FloatRect & to)987 TransformationMatrix TransformationMatrix::rectToRect(const FloatRect& from, const FloatRect& to)
988 {
989     ASSERT(!from.isEmpty());
990     return TransformationMatrix(to.width() / from.width(),
991                                 0, 0,
992                                 to.height() / from.height(),
993                                 to.x() - from.x(),
994                                 to.y() - from.y());
995 }
996 
997 // this = mat * this.
multiply(const TransformationMatrix & mat)998 TransformationMatrix& TransformationMatrix::multiply(const TransformationMatrix& mat)
999 {
1000 #if CPU(ARM64)
1001     double* rightMatrix = &(m_matrix[0][0]);
1002     const double* leftMatrix = &(mat.m_matrix[0][0]);
1003     asm volatile(
1004         // Load mat.m_matrix to v16 - v23.
1005         // Load this.m_matrix to v24 - v31.
1006         // Result: this = mat * this
1007         // | v0, v1 |   | v16, v17 |   | v24, v25 |
1008         // | v2, v3 | = | v18, v19 | * | v26, v27 |
1009         // | v4, v5 |   | v20, v21 |   | v28, v29 |
1010         // | v6, v7 |   | v22, v23 |   | v30, v31 |
1011         "mov x9, %[rightMatrix]   \t\n"
1012         "ld1 {v16.2d - v19.2d}, [%[leftMatrix]], 64  \t\n"
1013         "ld1 {v20.2d - v23.2d}, [%[leftMatrix]]      \t\n"
1014         "ld1 {v24.2d - v27.2d}, [%[rightMatrix]], 64 \t\n"
1015         "ld1 {v28.2d - v31.2d}, [%[rightMatrix]]     \t\n"
1016 
1017         "fmul v0.2d, v24.2d, v16.d[0]  \t\n"
1018         "fmul v1.2d, v25.2d, v16.d[0]  \t\n"
1019         "fmul v2.2d, v24.2d, v18.d[0]  \t\n"
1020         "fmul v3.2d, v25.2d, v18.d[0]  \t\n"
1021         "fmul v4.2d, v24.2d, v20.d[0]  \t\n"
1022         "fmul v5.2d, v25.2d, v20.d[0]  \t\n"
1023         "fmul v6.2d, v24.2d, v22.d[0]  \t\n"
1024         "fmul v7.2d, v25.2d, v22.d[0]  \t\n"
1025 
1026         "fmla v0.2d, v26.2d, v16.d[1]  \t\n"
1027         "fmla v1.2d, v27.2d, v16.d[1]  \t\n"
1028         "fmla v2.2d, v26.2d, v18.d[1]  \t\n"
1029         "fmla v3.2d, v27.2d, v18.d[1]  \t\n"
1030         "fmla v4.2d, v26.2d, v20.d[1]  \t\n"
1031         "fmla v5.2d, v27.2d, v20.d[1]  \t\n"
1032         "fmla v6.2d, v26.2d, v22.d[1]  \t\n"
1033         "fmla v7.2d, v27.2d, v22.d[1]  \t\n"
1034 
1035         "fmla v0.2d, v28.2d, v17.d[0]  \t\n"
1036         "fmla v1.2d, v29.2d, v17.d[0]  \t\n"
1037         "fmla v2.2d, v28.2d, v19.d[0]  \t\n"
1038         "fmla v3.2d, v29.2d, v19.d[0]  \t\n"
1039         "fmla v4.2d, v28.2d, v21.d[0]  \t\n"
1040         "fmla v5.2d, v29.2d, v21.d[0]  \t\n"
1041         "fmla v6.2d, v28.2d, v23.d[0]  \t\n"
1042         "fmla v7.2d, v29.2d, v23.d[0]  \t\n"
1043 
1044         "fmla v0.2d, v30.2d, v17.d[1]  \t\n"
1045         "fmla v1.2d, v31.2d, v17.d[1]  \t\n"
1046         "fmla v2.2d, v30.2d, v19.d[1]  \t\n"
1047         "fmla v3.2d, v31.2d, v19.d[1]  \t\n"
1048         "fmla v4.2d, v30.2d, v21.d[1]  \t\n"
1049         "fmla v5.2d, v31.2d, v21.d[1]  \t\n"
1050         "fmla v6.2d, v30.2d, v23.d[1]  \t\n"
1051         "fmla v7.2d, v31.2d, v23.d[1]  \t\n"
1052 
1053         "st1 {v0.2d - v3.2d}, [x9], 64 \t\n"
1054         "st1 {v4.2d - v7.2d}, [x9]     \t\n"
1055         : [leftMatrix]"+r"(leftMatrix), [rightMatrix]"+r"(rightMatrix)
1056         :
1057         : "memory", "x9", "v16", "v17", "v18", "v19", "v20", "v21", "v22",
1058             "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31",
1059             "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7"
1060     );
1061 #elif CPU(APPLE_ARMV7S)
1062     double* leftMatrix = &(m_matrix[0][0]);
1063     const double* rightMatrix = &(mat.m_matrix[0][0]);
1064     asm volatile (// First row of leftMatrix.
1065         "mov        r3, %[leftMatrix]\n\t"
1066         "vld1.64    { d16-d19 }, [%[leftMatrix], :128]!\n\t"
1067         "vld1.64    { d0-d3}, [%[rightMatrix], :128]!\n\t"
1068         "vmul.f64   d4, d0, d16\n\t"
1069         "vld1.64    { d20-d23 }, [%[leftMatrix], :128]!\n\t"
1070         "vmla.f64   d4, d1, d20\n\t"
1071         "vld1.64    { d24-d27 }, [%[leftMatrix], :128]!\n\t"
1072         "vmla.f64   d4, d2, d24\n\t"
1073         "vld1.64    { d28-d31 }, [%[leftMatrix], :128]!\n\t"
1074         "vmla.f64   d4, d3, d28\n\t"
1075 
1076         "vmul.f64   d5, d0, d17\n\t"
1077         "vmla.f64   d5, d1, d21\n\t"
1078         "vmla.f64   d5, d2, d25\n\t"
1079         "vmla.f64   d5, d3, d29\n\t"
1080 
1081         "vmul.f64   d6, d0, d18\n\t"
1082         "vmla.f64   d6, d1, d22\n\t"
1083         "vmla.f64   d6, d2, d26\n\t"
1084         "vmla.f64   d6, d3, d30\n\t"
1085 
1086         "vmul.f64   d7, d0, d19\n\t"
1087         "vmla.f64   d7, d1, d23\n\t"
1088         "vmla.f64   d7, d2, d27\n\t"
1089         "vmla.f64   d7, d3, d31\n\t"
1090         "vld1.64    { d0-d3}, [%[rightMatrix], :128]!\n\t"
1091         "vst1.64    { d4-d7 }, [r3, :128]!\n\t"
1092 
1093         // Second row of leftMatrix.
1094         "vmul.f64   d4, d0, d16\n\t"
1095         "vmla.f64   d4, d1, d20\n\t"
1096         "vmla.f64   d4, d2, d24\n\t"
1097         "vmla.f64   d4, d3, d28\n\t"
1098 
1099         "vmul.f64   d5, d0, d17\n\t"
1100         "vmla.f64   d5, d1, d21\n\t"
1101         "vmla.f64   d5, d2, d25\n\t"
1102         "vmla.f64   d5, d3, d29\n\t"
1103 
1104         "vmul.f64   d6, d0, d18\n\t"
1105         "vmla.f64   d6, d1, d22\n\t"
1106         "vmla.f64   d6, d2, d26\n\t"
1107         "vmla.f64   d6, d3, d30\n\t"
1108 
1109         "vmul.f64   d7, d0, d19\n\t"
1110         "vmla.f64   d7, d1, d23\n\t"
1111         "vmla.f64   d7, d2, d27\n\t"
1112         "vmla.f64   d7, d3, d31\n\t"
1113         "vld1.64    { d0-d3}, [%[rightMatrix], :128]!\n\t"
1114         "vst1.64    { d4-d7 }, [r3, :128]!\n\t"
1115 
1116         // Third row of leftMatrix.
1117         "vmul.f64   d4, d0, d16\n\t"
1118         "vmla.f64   d4, d1, d20\n\t"
1119         "vmla.f64   d4, d2, d24\n\t"
1120         "vmla.f64   d4, d3, d28\n\t"
1121 
1122         "vmul.f64   d5, d0, d17\n\t"
1123         "vmla.f64   d5, d1, d21\n\t"
1124         "vmla.f64   d5, d2, d25\n\t"
1125         "vmla.f64   d5, d3, d29\n\t"
1126 
1127         "vmul.f64   d6, d0, d18\n\t"
1128         "vmla.f64   d6, d1, d22\n\t"
1129         "vmla.f64   d6, d2, d26\n\t"
1130         "vmla.f64   d6, d3, d30\n\t"
1131 
1132         "vmul.f64   d7, d0, d19\n\t"
1133         "vmla.f64   d7, d1, d23\n\t"
1134         "vmla.f64   d7, d2, d27\n\t"
1135         "vmla.f64   d7, d3, d31\n\t"
1136         "vld1.64    { d0-d3}, [%[rightMatrix], :128]\n\t"
1137         "vst1.64    { d4-d7 }, [r3, :128]!\n\t"
1138 
1139         // Fourth and last row of leftMatrix.
1140         "vmul.f64   d4, d0, d16\n\t"
1141         "vmla.f64   d4, d1, d20\n\t"
1142         "vmla.f64   d4, d2, d24\n\t"
1143         "vmla.f64   d4, d3, d28\n\t"
1144 
1145         "vmul.f64   d5, d0, d17\n\t"
1146         "vmla.f64   d5, d1, d21\n\t"
1147         "vmla.f64   d5, d2, d25\n\t"
1148         "vmla.f64   d5, d3, d29\n\t"
1149 
1150         "vmul.f64   d6, d0, d18\n\t"
1151         "vmla.f64   d6, d1, d22\n\t"
1152         "vmla.f64   d6, d2, d26\n\t"
1153         "vmla.f64   d6, d3, d30\n\t"
1154 
1155         "vmul.f64   d7, d0, d19\n\t"
1156         "vmla.f64   d7, d1, d23\n\t"
1157         "vmla.f64   d7, d2, d27\n\t"
1158         "vmla.f64   d7, d3, d31\n\t"
1159         "vst1.64    { d4-d7 }, [r3, :128]\n\t"
1160         : [leftMatrix]"+r"(leftMatrix), [rightMatrix]"+r"(rightMatrix)
1161         :
1162         : "memory", "r3", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31");
1163 #elif defined(TRANSFORMATION_MATRIX_USE_X86_64_SSE2)
1164     // x86_64 has 16 XMM registers which is enough to do the multiplication fully in registers.
1165     __m128d matrixBlockA = _mm_load_pd(&(m_matrix[0][0]));
1166     __m128d matrixBlockC = _mm_load_pd(&(m_matrix[1][0]));
1167     __m128d matrixBlockE = _mm_load_pd(&(m_matrix[2][0]));
1168     __m128d matrixBlockG = _mm_load_pd(&(m_matrix[3][0]));
1169 
1170     // First row.
1171     __m128d otherMatrixFirstParam = _mm_set1_pd(mat.m_matrix[0][0]);
1172     __m128d otherMatrixSecondParam = _mm_set1_pd(mat.m_matrix[0][1]);
1173     __m128d otherMatrixThirdParam = _mm_set1_pd(mat.m_matrix[0][2]);
1174     __m128d otherMatrixFourthParam = _mm_set1_pd(mat.m_matrix[0][3]);
1175 
1176     // output00 and output01.
1177     __m128d accumulator = _mm_mul_pd(matrixBlockA, otherMatrixFirstParam);
1178     __m128d temp1 = _mm_mul_pd(matrixBlockC, otherMatrixSecondParam);
1179     __m128d temp2 = _mm_mul_pd(matrixBlockE, otherMatrixThirdParam);
1180     __m128d temp3 = _mm_mul_pd(matrixBlockG, otherMatrixFourthParam);
1181 
1182     __m128d matrixBlockB = _mm_load_pd(&(m_matrix[0][2]));
1183     __m128d matrixBlockD = _mm_load_pd(&(m_matrix[1][2]));
1184     __m128d matrixBlockF = _mm_load_pd(&(m_matrix[2][2]));
1185     __m128d matrixBlockH = _mm_load_pd(&(m_matrix[3][2]));
1186 
1187     accumulator = _mm_add_pd(accumulator, temp1);
1188     accumulator = _mm_add_pd(accumulator, temp2);
1189     accumulator = _mm_add_pd(accumulator, temp3);
1190     _mm_store_pd(&m_matrix[0][0], accumulator);
1191 
1192     // output02 and output03.
1193     accumulator = _mm_mul_pd(matrixBlockB, otherMatrixFirstParam);
1194     temp1 = _mm_mul_pd(matrixBlockD, otherMatrixSecondParam);
1195     temp2 = _mm_mul_pd(matrixBlockF, otherMatrixThirdParam);
1196     temp3 = _mm_mul_pd(matrixBlockH, otherMatrixFourthParam);
1197 
1198     accumulator = _mm_add_pd(accumulator, temp1);
1199     accumulator = _mm_add_pd(accumulator, temp2);
1200     accumulator = _mm_add_pd(accumulator, temp3);
1201     _mm_store_pd(&m_matrix[0][2], accumulator);
1202 
1203     // Second row.
1204     otherMatrixFirstParam = _mm_set1_pd(mat.m_matrix[1][0]);
1205     otherMatrixSecondParam = _mm_set1_pd(mat.m_matrix[1][1]);
1206     otherMatrixThirdParam = _mm_set1_pd(mat.m_matrix[1][2]);
1207     otherMatrixFourthParam = _mm_set1_pd(mat.m_matrix[1][3]);
1208 
1209     // output10 and output11.
1210     accumulator = _mm_mul_pd(matrixBlockA, otherMatrixFirstParam);
1211     temp1 = _mm_mul_pd(matrixBlockC, otherMatrixSecondParam);
1212     temp2 = _mm_mul_pd(matrixBlockE, otherMatrixThirdParam);
1213     temp3 = _mm_mul_pd(matrixBlockG, otherMatrixFourthParam);
1214 
1215     accumulator = _mm_add_pd(accumulator, temp1);
1216     accumulator = _mm_add_pd(accumulator, temp2);
1217     accumulator = _mm_add_pd(accumulator, temp3);
1218     _mm_store_pd(&m_matrix[1][0], accumulator);
1219 
1220     // output12 and output13.
1221     accumulator = _mm_mul_pd(matrixBlockB, otherMatrixFirstParam);
1222     temp1 = _mm_mul_pd(matrixBlockD, otherMatrixSecondParam);
1223     temp2 = _mm_mul_pd(matrixBlockF, otherMatrixThirdParam);
1224     temp3 = _mm_mul_pd(matrixBlockH, otherMatrixFourthParam);
1225 
1226     accumulator = _mm_add_pd(accumulator, temp1);
1227     accumulator = _mm_add_pd(accumulator, temp2);
1228     accumulator = _mm_add_pd(accumulator, temp3);
1229     _mm_store_pd(&m_matrix[1][2], accumulator);
1230 
1231     // Third row.
1232     otherMatrixFirstParam = _mm_set1_pd(mat.m_matrix[2][0]);
1233     otherMatrixSecondParam = _mm_set1_pd(mat.m_matrix[2][1]);
1234     otherMatrixThirdParam = _mm_set1_pd(mat.m_matrix[2][2]);
1235     otherMatrixFourthParam = _mm_set1_pd(mat.m_matrix[2][3]);
1236 
1237     // output20 and output21.
1238     accumulator = _mm_mul_pd(matrixBlockA, otherMatrixFirstParam);
1239     temp1 = _mm_mul_pd(matrixBlockC, otherMatrixSecondParam);
1240     temp2 = _mm_mul_pd(matrixBlockE, otherMatrixThirdParam);
1241     temp3 = _mm_mul_pd(matrixBlockG, otherMatrixFourthParam);
1242 
1243     accumulator = _mm_add_pd(accumulator, temp1);
1244     accumulator = _mm_add_pd(accumulator, temp2);
1245     accumulator = _mm_add_pd(accumulator, temp3);
1246     _mm_store_pd(&m_matrix[2][0], accumulator);
1247 
1248     // output22 and output23.
1249     accumulator = _mm_mul_pd(matrixBlockB, otherMatrixFirstParam);
1250     temp1 = _mm_mul_pd(matrixBlockD, otherMatrixSecondParam);
1251     temp2 = _mm_mul_pd(matrixBlockF, otherMatrixThirdParam);
1252     temp3 = _mm_mul_pd(matrixBlockH, otherMatrixFourthParam);
1253 
1254     accumulator = _mm_add_pd(accumulator, temp1);
1255     accumulator = _mm_add_pd(accumulator, temp2);
1256     accumulator = _mm_add_pd(accumulator, temp3);
1257     _mm_store_pd(&m_matrix[2][2], accumulator);
1258 
1259     // Fourth row.
1260     otherMatrixFirstParam = _mm_set1_pd(mat.m_matrix[3][0]);
1261     otherMatrixSecondParam = _mm_set1_pd(mat.m_matrix[3][1]);
1262     otherMatrixThirdParam = _mm_set1_pd(mat.m_matrix[3][2]);
1263     otherMatrixFourthParam = _mm_set1_pd(mat.m_matrix[3][3]);
1264 
1265     // output30 and output31.
1266     accumulator = _mm_mul_pd(matrixBlockA, otherMatrixFirstParam);
1267     temp1 = _mm_mul_pd(matrixBlockC, otherMatrixSecondParam);
1268     temp2 = _mm_mul_pd(matrixBlockE, otherMatrixThirdParam);
1269     temp3 = _mm_mul_pd(matrixBlockG, otherMatrixFourthParam);
1270 
1271     accumulator = _mm_add_pd(accumulator, temp1);
1272     accumulator = _mm_add_pd(accumulator, temp2);
1273     accumulator = _mm_add_pd(accumulator, temp3);
1274     _mm_store_pd(&m_matrix[3][0], accumulator);
1275 
1276     // output32 and output33.
1277     accumulator = _mm_mul_pd(matrixBlockB, otherMatrixFirstParam);
1278     temp1 = _mm_mul_pd(matrixBlockD, otherMatrixSecondParam);
1279     temp2 = _mm_mul_pd(matrixBlockF, otherMatrixThirdParam);
1280     temp3 = _mm_mul_pd(matrixBlockH, otherMatrixFourthParam);
1281 
1282     accumulator = _mm_add_pd(accumulator, temp1);
1283     accumulator = _mm_add_pd(accumulator, temp2);
1284     accumulator = _mm_add_pd(accumulator, temp3);
1285     _mm_store_pd(&m_matrix[3][2], accumulator);
1286 #else
1287     Matrix4 tmp;
1288 
1289     tmp[0][0] = (mat.m_matrix[0][0] * m_matrix[0][0] + mat.m_matrix[0][1] * m_matrix[1][0]
1290                + mat.m_matrix[0][2] * m_matrix[2][0] + mat.m_matrix[0][3] * m_matrix[3][0]);
1291     tmp[0][1] = (mat.m_matrix[0][0] * m_matrix[0][1] + mat.m_matrix[0][1] * m_matrix[1][1]
1292                + mat.m_matrix[0][2] * m_matrix[2][1] + mat.m_matrix[0][3] * m_matrix[3][1]);
1293     tmp[0][2] = (mat.m_matrix[0][0] * m_matrix[0][2] + mat.m_matrix[0][1] * m_matrix[1][2]
1294                + mat.m_matrix[0][2] * m_matrix[2][2] + mat.m_matrix[0][3] * m_matrix[3][2]);
1295     tmp[0][3] = (mat.m_matrix[0][0] * m_matrix[0][3] + mat.m_matrix[0][1] * m_matrix[1][3]
1296                + mat.m_matrix[0][2] * m_matrix[2][3] + mat.m_matrix[0][3] * m_matrix[3][3]);
1297 
1298     tmp[1][0] = (mat.m_matrix[1][0] * m_matrix[0][0] + mat.m_matrix[1][1] * m_matrix[1][0]
1299                + mat.m_matrix[1][2] * m_matrix[2][0] + mat.m_matrix[1][3] * m_matrix[3][0]);
1300     tmp[1][1] = (mat.m_matrix[1][0] * m_matrix[0][1] + mat.m_matrix[1][1] * m_matrix[1][1]
1301                + mat.m_matrix[1][2] * m_matrix[2][1] + mat.m_matrix[1][3] * m_matrix[3][1]);
1302     tmp[1][2] = (mat.m_matrix[1][0] * m_matrix[0][2] + mat.m_matrix[1][1] * m_matrix[1][2]
1303                + mat.m_matrix[1][2] * m_matrix[2][2] + mat.m_matrix[1][3] * m_matrix[3][2]);
1304     tmp[1][3] = (mat.m_matrix[1][0] * m_matrix[0][3] + mat.m_matrix[1][1] * m_matrix[1][3]
1305                + mat.m_matrix[1][2] * m_matrix[2][3] + mat.m_matrix[1][3] * m_matrix[3][3]);
1306 
1307     tmp[2][0] = (mat.m_matrix[2][0] * m_matrix[0][0] + mat.m_matrix[2][1] * m_matrix[1][0]
1308                + mat.m_matrix[2][2] * m_matrix[2][0] + mat.m_matrix[2][3] * m_matrix[3][0]);
1309     tmp[2][1] = (mat.m_matrix[2][0] * m_matrix[0][1] + mat.m_matrix[2][1] * m_matrix[1][1]
1310                + mat.m_matrix[2][2] * m_matrix[2][1] + mat.m_matrix[2][3] * m_matrix[3][1]);
1311     tmp[2][2] = (mat.m_matrix[2][0] * m_matrix[0][2] + mat.m_matrix[2][1] * m_matrix[1][2]
1312                + mat.m_matrix[2][2] * m_matrix[2][2] + mat.m_matrix[2][3] * m_matrix[3][2]);
1313     tmp[2][3] = (mat.m_matrix[2][0] * m_matrix[0][3] + mat.m_matrix[2][1] * m_matrix[1][3]
1314                + mat.m_matrix[2][2] * m_matrix[2][3] + mat.m_matrix[2][3] * m_matrix[3][3]);
1315 
1316     tmp[3][0] = (mat.m_matrix[3][0] * m_matrix[0][0] + mat.m_matrix[3][1] * m_matrix[1][0]
1317                + mat.m_matrix[3][2] * m_matrix[2][0] + mat.m_matrix[3][3] * m_matrix[3][0]);
1318     tmp[3][1] = (mat.m_matrix[3][0] * m_matrix[0][1] + mat.m_matrix[3][1] * m_matrix[1][1]
1319                + mat.m_matrix[3][2] * m_matrix[2][1] + mat.m_matrix[3][3] * m_matrix[3][1]);
1320     tmp[3][2] = (mat.m_matrix[3][0] * m_matrix[0][2] + mat.m_matrix[3][1] * m_matrix[1][2]
1321                + mat.m_matrix[3][2] * m_matrix[2][2] + mat.m_matrix[3][3] * m_matrix[3][2]);
1322     tmp[3][3] = (mat.m_matrix[3][0] * m_matrix[0][3] + mat.m_matrix[3][1] * m_matrix[1][3]
1323                + mat.m_matrix[3][2] * m_matrix[2][3] + mat.m_matrix[3][3] * m_matrix[3][3]);
1324 
1325     setMatrix(tmp);
1326 #endif
1327     return *this;
1328 }
1329 
multVecMatrix(double x,double y,double & resultX,double & resultY) const1330 void TransformationMatrix::multVecMatrix(double x, double y, double& resultX, double& resultY) const
1331 {
1332     resultX = m_matrix[3][0] + x * m_matrix[0][0] + y * m_matrix[1][0];
1333     resultY = m_matrix[3][1] + x * m_matrix[0][1] + y * m_matrix[1][1];
1334     double w = m_matrix[3][3] + x * m_matrix[0][3] + y * m_matrix[1][3];
1335     if (w != 1 && w != 0) {
1336         resultX /= w;
1337         resultY /= w;
1338     }
1339 }
1340 
multVecMatrix(double x,double y,double z,double & resultX,double & resultY,double & resultZ) const1341 void TransformationMatrix::multVecMatrix(double x, double y, double z, double& resultX, double& resultY, double& resultZ) const
1342 {
1343     resultX = m_matrix[3][0] + x * m_matrix[0][0] + y * m_matrix[1][0] + z * m_matrix[2][0];
1344     resultY = m_matrix[3][1] + x * m_matrix[0][1] + y * m_matrix[1][1] + z * m_matrix[2][1];
1345     resultZ = m_matrix[3][2] + x * m_matrix[0][2] + y * m_matrix[1][2] + z * m_matrix[2][2];
1346     double w = m_matrix[3][3] + x * m_matrix[0][3] + y * m_matrix[1][3] + z * m_matrix[2][3];
1347     if (w != 1 && w != 0) {
1348         resultX /= w;
1349         resultY /= w;
1350         resultZ /= w;
1351     }
1352 }
1353 
isInvertible() const1354 bool TransformationMatrix::isInvertible() const
1355 {
1356     if (isIdentityOrTranslation())
1357         return true;
1358 
1359     double det = blink::determinant4x4(m_matrix);
1360 
1361     if (fabs(det) < SMALL_NUMBER)
1362         return false;
1363 
1364     return true;
1365 }
1366 
inverse() const1367 TransformationMatrix TransformationMatrix::inverse() const
1368 {
1369     if (isIdentityOrTranslation()) {
1370         // identity matrix
1371         if (m_matrix[3][0] == 0 && m_matrix[3][1] == 0 && m_matrix[3][2] == 0)
1372             return TransformationMatrix();
1373 
1374         // translation
1375         return TransformationMatrix(1, 0, 0, 0,
1376                                     0, 1, 0, 0,
1377                                     0, 0, 1, 0,
1378                                     -m_matrix[3][0], -m_matrix[3][1], -m_matrix[3][2], 1);
1379     }
1380 
1381     TransformationMatrix invMat;
1382     bool inverted = blink::inverse(m_matrix, invMat.m_matrix);
1383     if (!inverted)
1384         return TransformationMatrix();
1385 
1386     return invMat;
1387 }
1388 
makeAffine()1389 void TransformationMatrix::makeAffine()
1390 {
1391     m_matrix[0][2] = 0;
1392     m_matrix[0][3] = 0;
1393 
1394     m_matrix[1][2] = 0;
1395     m_matrix[1][3] = 0;
1396 
1397     m_matrix[2][0] = 0;
1398     m_matrix[2][1] = 0;
1399     m_matrix[2][2] = 1;
1400     m_matrix[2][3] = 0;
1401 
1402     m_matrix[3][2] = 0;
1403     m_matrix[3][3] = 1;
1404 }
1405 
toAffineTransform() const1406 AffineTransform TransformationMatrix::toAffineTransform() const
1407 {
1408     return AffineTransform(m_matrix[0][0], m_matrix[0][1], m_matrix[1][0],
1409                            m_matrix[1][1], m_matrix[3][0], m_matrix[3][1]);
1410 }
1411 
blendFloat(double & from,double to,double progress)1412 static inline void blendFloat(double& from, double to, double progress)
1413 {
1414     if (from != to)
1415         from = from + (to - from) * progress;
1416 }
1417 
blend(const TransformationMatrix & from,double progress)1418 void TransformationMatrix::blend(const TransformationMatrix& from, double progress)
1419 {
1420     if (from.isIdentity() && isIdentity())
1421         return;
1422 
1423     // decompose
1424     DecomposedType fromDecomp;
1425     DecomposedType toDecomp;
1426     if (!from.decompose(fromDecomp) || !decompose(toDecomp)) {
1427         if (progress < 0.5)
1428             *this = from;
1429         return;
1430     }
1431 
1432     // interpolate
1433     blendFloat(fromDecomp.scaleX, toDecomp.scaleX, progress);
1434     blendFloat(fromDecomp.scaleY, toDecomp.scaleY, progress);
1435     blendFloat(fromDecomp.scaleZ, toDecomp.scaleZ, progress);
1436     blendFloat(fromDecomp.skewXY, toDecomp.skewXY, progress);
1437     blendFloat(fromDecomp.skewXZ, toDecomp.skewXZ, progress);
1438     blendFloat(fromDecomp.skewYZ, toDecomp.skewYZ, progress);
1439     blendFloat(fromDecomp.translateX, toDecomp.translateX, progress);
1440     blendFloat(fromDecomp.translateY, toDecomp.translateY, progress);
1441     blendFloat(fromDecomp.translateZ, toDecomp.translateZ, progress);
1442     blendFloat(fromDecomp.perspectiveX, toDecomp.perspectiveX, progress);
1443     blendFloat(fromDecomp.perspectiveY, toDecomp.perspectiveY, progress);
1444     blendFloat(fromDecomp.perspectiveZ, toDecomp.perspectiveZ, progress);
1445     blendFloat(fromDecomp.perspectiveW, toDecomp.perspectiveW, progress);
1446 
1447     slerp(&fromDecomp.quaternionX, &toDecomp.quaternionX, progress);
1448 
1449     // recompose
1450     recompose(fromDecomp);
1451 }
1452 
decompose(DecomposedType & decomp) const1453 bool TransformationMatrix::decompose(DecomposedType& decomp) const
1454 {
1455     if (isIdentity()) {
1456         memset(&decomp, 0, sizeof(decomp));
1457         decomp.perspectiveW = 1;
1458         decomp.scaleX = 1;
1459         decomp.scaleY = 1;
1460         decomp.scaleZ = 1;
1461     }
1462 
1463     if (!blink::decompose(m_matrix, decomp))
1464         return false;
1465     return true;
1466 }
1467 
recompose(const DecomposedType & decomp)1468 void TransformationMatrix::recompose(const DecomposedType& decomp)
1469 {
1470     makeIdentity();
1471 
1472     // first apply perspective
1473     m_matrix[0][3] = decomp.perspectiveX;
1474     m_matrix[1][3] = decomp.perspectiveY;
1475     m_matrix[2][3] = decomp.perspectiveZ;
1476     m_matrix[3][3] = decomp.perspectiveW;
1477 
1478     // now translate
1479     translate3d(decomp.translateX, decomp.translateY, decomp.translateZ);
1480 
1481     // apply rotation
1482     double xx = decomp.quaternionX * decomp.quaternionX;
1483     double xy = decomp.quaternionX * decomp.quaternionY;
1484     double xz = decomp.quaternionX * decomp.quaternionZ;
1485     double xw = decomp.quaternionX * decomp.quaternionW;
1486     double yy = decomp.quaternionY * decomp.quaternionY;
1487     double yz = decomp.quaternionY * decomp.quaternionZ;
1488     double yw = decomp.quaternionY * decomp.quaternionW;
1489     double zz = decomp.quaternionZ * decomp.quaternionZ;
1490     double zw = decomp.quaternionZ * decomp.quaternionW;
1491 
1492     // Construct a composite rotation matrix from the quaternion values
1493     TransformationMatrix rotationMatrix(1 - 2 * (yy + zz), 2 * (xy - zw), 2 * (xz + yw), 0,
1494                            2 * (xy + zw), 1 - 2 * (xx + zz), 2 * (yz - xw), 0,
1495                            2 * (xz - yw), 2 * (yz + xw), 1 - 2 * (xx + yy), 0,
1496                            0, 0, 0, 1);
1497 
1498     multiply(rotationMatrix);
1499 
1500     // now apply skew
1501     if (decomp.skewYZ) {
1502         TransformationMatrix tmp;
1503         tmp.setM32(decomp.skewYZ);
1504         multiply(tmp);
1505     }
1506 
1507     if (decomp.skewXZ) {
1508         TransformationMatrix tmp;
1509         tmp.setM31(decomp.skewXZ);
1510         multiply(tmp);
1511     }
1512 
1513     if (decomp.skewXY) {
1514         TransformationMatrix tmp;
1515         tmp.setM21(decomp.skewXY);
1516         multiply(tmp);
1517     }
1518 
1519     // finally, apply scale
1520     scale3d(decomp.scaleX, decomp.scaleY, decomp.scaleZ);
1521 }
1522 
isIntegerTranslation() const1523 bool TransformationMatrix::isIntegerTranslation() const
1524 {
1525     if (!isIdentityOrTranslation())
1526         return false;
1527 
1528     // Check for translate Z.
1529     if (m_matrix[3][2])
1530         return false;
1531 
1532     // Check for non-integer translate X/Y.
1533     if (static_cast<int>(m_matrix[3][0]) != m_matrix[3][0] || static_cast<int>(m_matrix[3][1]) != m_matrix[3][1])
1534         return false;
1535 
1536     return true;
1537 }
1538 
to2dTransform() const1539 TransformationMatrix TransformationMatrix::to2dTransform() const
1540 {
1541     return TransformationMatrix(m_matrix[0][0], m_matrix[0][1], 0, m_matrix[0][3],
1542                                 m_matrix[1][0], m_matrix[1][1], 0, m_matrix[1][3],
1543                                 0, 0, 1, 0,
1544                                 m_matrix[3][0], m_matrix[3][1], 0, m_matrix[3][3]);
1545 }
1546 
toColumnMajorFloatArray(FloatMatrix4 & result) const1547 void TransformationMatrix::toColumnMajorFloatArray(FloatMatrix4& result) const
1548 {
1549     result[0] = m11();
1550     result[1] = m12();
1551     result[2] = m13();
1552     result[3] = m14();
1553     result[4] = m21();
1554     result[5] = m22();
1555     result[6] = m23();
1556     result[7] = m24();
1557     result[8] = m31();
1558     result[9] = m32();
1559     result[10] = m33();
1560     result[11] = m34();
1561     result[12] = m41();
1562     result[13] = m42();
1563     result[14] = m43();
1564     result[15] = m44();
1565 }
1566 
toSkMatrix44(const TransformationMatrix & matrix)1567 SkMatrix44 TransformationMatrix::toSkMatrix44(const TransformationMatrix& matrix)
1568 {
1569     SkMatrix44 ret(SkMatrix44::kUninitialized_Constructor);
1570     ret.setDouble(0, 0, matrix.m11());
1571     ret.setDouble(0, 1, matrix.m21());
1572     ret.setDouble(0, 2, matrix.m31());
1573     ret.setDouble(0, 3, matrix.m41());
1574     ret.setDouble(1, 0, matrix.m12());
1575     ret.setDouble(1, 1, matrix.m22());
1576     ret.setDouble(1, 2, matrix.m32());
1577     ret.setDouble(1, 3, matrix.m42());
1578     ret.setDouble(2, 0, matrix.m13());
1579     ret.setDouble(2, 1, matrix.m23());
1580     ret.setDouble(2, 2, matrix.m33());
1581     ret.setDouble(2, 3, matrix.m43());
1582     ret.setDouble(3, 0, matrix.m14());
1583     ret.setDouble(3, 1, matrix.m24());
1584     ret.setDouble(3, 2, matrix.m34());
1585     ret.setDouble(3, 3, matrix.m44());
1586     return ret;
1587 }
1588 
1589 }
1590