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 "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
29
30 #include <cmath>
31 #include <cstdlib>
32
33 #include "base/compiler_specific.h"
34 #include "third_party/blink/renderer/platform/geometry/float_box.h"
35 #include "third_party/blink/renderer/platform/geometry/float_quad.h"
36 #include "third_party/blink/renderer/platform/geometry/float_rect.h"
37 #include "third_party/blink/renderer/platform/geometry/int_rect.h"
38 #include "third_party/blink/renderer/platform/geometry/layout_rect.h"
39 #include "third_party/blink/renderer/platform/json/json_values.h"
40 #include "third_party/blink/renderer/platform/transforms/affine_transform.h"
41 #include "third_party/blink/renderer/platform/transforms/rotation.h"
42 #include "third_party/blink/renderer/platform/wtf/assertions.h"
43 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
44 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
45 #include "ui/gfx/geometry/quaternion.h"
46 #include "ui/gfx/transform.h"
47
48 #if defined(ARCH_CPU_X86_64)
49 #include <emmintrin.h>
50 #endif
51
52 #if defined(HAVE_MIPS_MSA_INTRINSICS)
53 #include "third_party/blink/renderer/platform/cpu/mips/common_macros_msa.h"
54 #endif
55
56 namespace blink {
57
58 using gfx::Quaternion;
59
60 //
61 // Supporting Math Functions
62 //
63 // This is a set of function from various places (attributed inline) to do
64 // things like inversion and decomposition of a 4x4 matrix. They are used
65 // throughout the code
66 //
67
68 //
69 // Adapted from Matrix Inversion by Richard Carling, Graphics Gems
70 // <http://tog.acm.org/GraphicsGems/index.html>.
71
72 // EULA: The Graphics Gems code is copyright-protected. In other words, you
73 // cannot claim the text of the code as your own and resell it. Using the code
74 // is permitted in any program, product, or library, non-commercial or
75 // commercial. Giving credit is not required, though is a nice gesture. The code
76 // comes as-is, and if there are any flaws or problems with any Gems code,
77 // nobody involved with Gems - authors, editors, publishers, or webmasters - are
78 // to be held responsible. Basically, don't be a jerk, and remember that
79 // anything free comes with no guarantee.
80
81 typedef double Vector4[4];
82 typedef double Vector3[3];
83
84 // inverse(original_matrix, inverse_matrix)
85 //
86 // calculate the inverse of a 4x4 matrix
87 //
88 // -1
89 // A = ___1__ adjoint A
90 // det A
91
92 // double = determinant2x2(double a, double b, double c, double d)
93 //
94 // calculate the determinant of a 2x2 matrix.
95
Determinant2x2(double a,double b,double c,double d)96 static double Determinant2x2(double a, double b, double c, double d) {
97 return a * d - b * c;
98 }
99
100 // double = determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3)
101 //
102 // Calculate the determinant of a 3x3 matrix
103 // in the form
104 //
105 // | a1, b1, c1 |
106 // | a2, b2, c2 |
107 // | a3, b3, c3 |
108
Determinant3x3(double a1,double a2,double a3,double b1,double b2,double b3,double c1,double c2,double c3)109 static double Determinant3x3(double a1,
110 double a2,
111 double a3,
112 double b1,
113 double b2,
114 double b3,
115 double c1,
116 double c2,
117 double c3) {
118 return a1 * Determinant2x2(b2, b3, c2, c3) -
119 b1 * Determinant2x2(a2, a3, c2, c3) +
120 c1 * Determinant2x2(a2, a3, b2, b3);
121 }
122
123 // double = determinant4x4(matrix)
124 //
125 // calculate the determinant of a 4x4 matrix.
126
Determinant4x4(const TransformationMatrix::Matrix4 & m)127 static double Determinant4x4(const TransformationMatrix::Matrix4& m) {
128 // Assign to individual variable names to aid selecting
129 // correct elements
130
131 double a1 = m[0][0];
132 double b1 = m[0][1];
133 double c1 = m[0][2];
134 double d1 = m[0][3];
135
136 double a2 = m[1][0];
137 double b2 = m[1][1];
138 double c2 = m[1][2];
139 double d2 = m[1][3];
140
141 double a3 = m[2][0];
142 double b3 = m[2][1];
143 double c3 = m[2][2];
144 double d3 = m[2][3];
145
146 double a4 = m[3][0];
147 double b4 = m[3][1];
148 double c4 = m[3][2];
149 double d4 = m[3][3];
150
151 return a1 * Determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4) -
152 b1 * Determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4) +
153 c1 * Determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4) -
154 d1 * Determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);
155 }
156
157 #if !defined(ARCH_CPU_ARM64) && !HAVE_MIPS_MSA_INTRINSICS
158 // adjoint( original_matrix, inverse_matrix )
159 //
160 // calculate the adjoint of a 4x4 matrix
161 //
162 // Let a denote the minor determinant of matrix A obtained by
163 // ij
164 //
165 // deleting the ith row and jth column from A.
166 //
167 // i+j
168 // Let b = (-1) a
169 // ij ji
170 //
171 // The matrix B = (b ) is the adjoint of A
172 // ij
173
Adjoint(const TransformationMatrix::Matrix4 & matrix,TransformationMatrix::Matrix4 & result)174 static inline void Adjoint(const TransformationMatrix::Matrix4& matrix,
175 TransformationMatrix::Matrix4& result) {
176 // Assign to individual variable names to aid
177 // selecting correct values
178 double a1 = matrix[0][0];
179 double b1 = matrix[0][1];
180 double c1 = matrix[0][2];
181 double d1 = matrix[0][3];
182
183 double a2 = matrix[1][0];
184 double b2 = matrix[1][1];
185 double c2 = matrix[1][2];
186 double d2 = matrix[1][3];
187
188 double a3 = matrix[2][0];
189 double b3 = matrix[2][1];
190 double c3 = matrix[2][2];
191 double d3 = matrix[2][3];
192
193 double a4 = matrix[3][0];
194 double b4 = matrix[3][1];
195 double c4 = matrix[3][2];
196 double d4 = matrix[3][3];
197
198 // Row column labeling reversed since we transpose rows & columns
199 result[0][0] = Determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4);
200 result[1][0] = -Determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4);
201 result[2][0] = Determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4);
202 result[3][0] = -Determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);
203
204 result[0][1] = -Determinant3x3(b1, b3, b4, c1, c3, c4, d1, d3, d4);
205 result[1][1] = Determinant3x3(a1, a3, a4, c1, c3, c4, d1, d3, d4);
206 result[2][1] = -Determinant3x3(a1, a3, a4, b1, b3, b4, d1, d3, d4);
207 result[3][1] = Determinant3x3(a1, a3, a4, b1, b3, b4, c1, c3, c4);
208
209 result[0][2] = Determinant3x3(b1, b2, b4, c1, c2, c4, d1, d2, d4);
210 result[1][2] = -Determinant3x3(a1, a2, a4, c1, c2, c4, d1, d2, d4);
211 result[2][2] = Determinant3x3(a1, a2, a4, b1, b2, b4, d1, d2, d4);
212 result[3][2] = -Determinant3x3(a1, a2, a4, b1, b2, b4, c1, c2, c4);
213
214 result[0][3] = -Determinant3x3(b1, b2, b3, c1, c2, c3, d1, d2, d3);
215 result[1][3] = Determinant3x3(a1, a2, a3, c1, c2, c3, d1, d2, d3);
216 result[2][3] = -Determinant3x3(a1, a2, a3, b1, b2, b3, d1, d2, d3);
217 result[3][3] = Determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3);
218 }
219 #endif
220
221 // Returns false if the matrix is not invertible
Inverse(const TransformationMatrix::Matrix4 & matrix,TransformationMatrix::Matrix4 & result)222 static bool Inverse(const TransformationMatrix::Matrix4& matrix,
223 TransformationMatrix::Matrix4& result) {
224 // Calculate the 4x4 determinant
225 // If the determinant is zero,
226 // then the inverse matrix is not unique.
227 double det = Determinant4x4(matrix);
228
229 if (det == 0)
230 return false;
231
232 #if defined(ARCH_CPU_ARM64)
233 double rdet = 1 / det;
234 const double* mat = &(matrix[0][0]);
235 double* pr = &(result[0][0]);
236 asm volatile(
237 // mat: v16 - v23
238 // m11, m12, m13, m14
239 // m21, m22, m23, m24
240 // m31, m32, m33, m34
241 // m41, m42, m43, m44
242 "ld1 {v16.2d - v19.2d}, [%[mat]], 64 \n\t"
243 "ld1 {v20.2d - v23.2d}, [%[mat]] \n\t"
244 "ins v30.d[0], %[rdet] \n\t"
245 // Determinant: right mat2x2
246 "trn1 v0.2d, v17.2d, v21.2d \n\t"
247 "trn2 v1.2d, v19.2d, v23.2d \n\t"
248 "trn2 v2.2d, v17.2d, v21.2d \n\t"
249 "trn1 v3.2d, v19.2d, v23.2d \n\t"
250 "trn2 v5.2d, v21.2d, v23.2d \n\t"
251 "trn1 v4.2d, v17.2d, v19.2d \n\t"
252 "trn2 v6.2d, v17.2d, v19.2d \n\t"
253 "trn1 v7.2d, v21.2d, v23.2d \n\t"
254 "trn2 v25.2d, v23.2d, v21.2d \n\t"
255 "trn1 v27.2d, v23.2d, v21.2d \n\t"
256 "fmul v0.2d, v0.2d, v1.2d \n\t"
257 "fmul v1.2d, v4.2d, v5.2d \n\t"
258 "fmls v0.2d, v2.2d, v3.2d \n\t"
259 "fmul v2.2d, v4.2d, v25.2d \n\t"
260 "fmls v1.2d, v6.2d, v7.2d \n\t"
261 "fmls v2.2d, v6.2d, v27.2d \n\t"
262 // Adjoint:
263 // v24: A11A12, v25: A13A14
264 // v26: A21A22, v27: A23A24
265 "fmul v3.2d, v18.2d, v0.d[1] \n\t"
266 "fmul v4.2d, v16.2d, v0.d[1] \n\t"
267 "fmul v5.2d, v16.2d, v1.d[1] \n\t"
268 "fmul v6.2d, v16.2d, v2.d[1] \n\t"
269 "fmls v3.2d, v20.2d, v1.d[1] \n\t"
270 "fmls v4.2d, v20.2d, v2.d[0] \n\t"
271 "fmls v5.2d, v18.2d, v2.d[0] \n\t"
272 "fmls v6.2d, v18.2d, v1.d[0] \n\t"
273 "fmla v3.2d, v22.2d, v2.d[1] \n\t"
274 "fmla v4.2d, v22.2d, v1.d[0] \n\t"
275 "fmla v5.2d, v22.2d, v0.d[0] \n\t"
276 "fmla v6.2d, v20.2d, v0.d[0] \n\t"
277 "fneg v3.2d, v3.2d \n\t"
278 "fneg v5.2d, v5.2d \n\t"
279 "trn1 v26.2d, v3.2d, v4.2d \n\t"
280 "trn1 v27.2d, v5.2d, v6.2d \n\t"
281 "trn2 v24.2d, v3.2d, v4.2d \n\t"
282 "trn2 v25.2d, v5.2d, v6.2d \n\t"
283 "fneg v24.2d, v24.2d \n\t"
284 "fneg v25.2d, v25.2d \n\t"
285 // Inverse
286 // v24: I11I12, v25: I13I14
287 // v26: I21I22, v27: I23I24
288 "fmul v24.2d, v24.2d, v30.d[0] \n\t"
289 "fmul v25.2d, v25.2d, v30.d[0] \n\t"
290 "fmul v26.2d, v26.2d, v30.d[0] \n\t"
291 "fmul v27.2d, v27.2d, v30.d[0] \n\t"
292 "st1 {v24.2d - v27.2d}, [%[pr]], 64 \n\t"
293 // Determinant: left mat2x2
294 "trn1 v0.2d, v16.2d, v20.2d \n\t"
295 "trn2 v1.2d, v18.2d, v22.2d \n\t"
296 "trn2 v2.2d, v16.2d, v20.2d \n\t"
297 "trn1 v3.2d, v18.2d, v22.2d \n\t"
298 "trn2 v5.2d, v20.2d, v22.2d \n\t"
299 "trn1 v4.2d, v16.2d, v18.2d \n\t"
300 "trn2 v6.2d, v16.2d, v18.2d \n\t"
301 "trn1 v7.2d, v20.2d, v22.2d \n\t"
302 "trn2 v25.2d, v22.2d, v20.2d \n\t"
303 "trn1 v27.2d, v22.2d, v20.2d \n\t"
304 "fmul v0.2d, v0.2d, v1.2d \n\t"
305 "fmul v1.2d, v4.2d, v5.2d \n\t"
306 "fmls v0.2d, v2.2d, v3.2d \n\t"
307 "fmul v2.2d, v4.2d, v25.2d \n\t"
308 "fmls v1.2d, v6.2d, v7.2d \n\t"
309 "fmls v2.2d, v6.2d, v27.2d \n\t"
310 // Adjoint:
311 // v24: A31A32, v25: A33A34
312 // v26: A41A42, v27: A43A44
313 "fmul v3.2d, v19.2d, v0.d[1] \n\t"
314 "fmul v4.2d, v17.2d, v0.d[1] \n\t"
315 "fmul v5.2d, v17.2d, v1.d[1] \n\t"
316 "fmul v6.2d, v17.2d, v2.d[1] \n\t"
317 "fmls v3.2d, v21.2d, v1.d[1] \n\t"
318 "fmls v4.2d, v21.2d, v2.d[0] \n\t"
319 "fmls v5.2d, v19.2d, v2.d[0] \n\t"
320 "fmls v6.2d, v19.2d, v1.d[0] \n\t"
321 "fmla v3.2d, v23.2d, v2.d[1] \n\t"
322 "fmla v4.2d, v23.2d, v1.d[0] \n\t"
323 "fmla v5.2d, v23.2d, v0.d[0] \n\t"
324 "fmla v6.2d, v21.2d, v0.d[0] \n\t"
325 "fneg v3.2d, v3.2d \n\t"
326 "fneg v5.2d, v5.2d \n\t"
327 "trn1 v26.2d, v3.2d, v4.2d \n\t"
328 "trn1 v27.2d, v5.2d, v6.2d \n\t"
329 "trn2 v24.2d, v3.2d, v4.2d \n\t"
330 "trn2 v25.2d, v5.2d, v6.2d \n\t"
331 "fneg v24.2d, v24.2d \n\t"
332 "fneg v25.2d, v25.2d \n\t"
333 // Inverse
334 // v24: I31I32, v25: I33I34
335 // v26: I41I42, v27: I43I44
336 "fmul v24.2d, v24.2d, v30.d[0] \n\t"
337 "fmul v25.2d, v25.2d, v30.d[0] \n\t"
338 "fmul v26.2d, v26.2d, v30.d[0] \n\t"
339 "fmul v27.2d, v27.2d, v30.d[0] \n\t"
340 "st1 {v24.2d - v27.2d}, [%[pr]] \n\t"
341 : [mat] "+r"(mat), [pr] "+r"(pr)
342 : [rdet] "r"(rdet)
343 : "memory", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v16", "v17",
344 "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27",
345 "v28", "v29", "v30");
346 #elif defined(HAVE_MIPS_MSA_INTRINSICS)
347 const double rDet = 1 / det;
348 const double* mat = &(matrix[0][0]);
349 v2f64 mat0, mat1, mat2, mat3, mat4, mat5, mat6, mat7;
350 v2f64 rev2, rev3, rev4, rev5, rev6, rev7;
351 v2f64 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
352 v2f64 det0, det1, det2, tmp8, tmp9, tmp10, tmp11;
353 const v2f64 rdet = COPY_DOUBLE_TO_VECTOR(rDet);
354 // mat0 mat1 --> m00 m01 m02 m03
355 // mat2 mat3 --> m10 m11 m12 m13
356 // mat4 mat5 --> m20 m21 m22 m23
357 // mat6 mat7 --> m30 m31 m32 m33
358 LD_DP8(mat, 2, mat0, mat1, mat2, mat3, mat4, mat5, mat6, mat7);
359
360 // Right half
361 rev3 = SLDI_D(mat3, mat3, 8); // m13 m12
362 rev5 = SLDI_D(mat5, mat5, 8); // m23 m22
363 rev7 = SLDI_D(mat7, mat7, 8); // m33 m32
364
365 // 2*2 Determinants
366 // for A00 & A01
367 tmp0 = mat5 * rev7;
368 tmp1 = mat3 * rev7;
369 tmp2 = mat3 * rev5;
370 // for A10 & A11
371 tmp3 = mat1 * rev7;
372 tmp4 = mat1 * rev5;
373 // for A20 & A21
374 tmp5 = mat1 * rev3;
375 // for A30 & A31
376 tmp6 = (v2f64)__msa_ilvr_d((v2i64)tmp1, (v2i64)tmp0);
377 tmp7 = (v2f64)__msa_ilvl_d((v2i64)tmp1, (v2i64)tmp0);
378 det0 = tmp6 - tmp7;
379 tmp6 = (v2f64)__msa_ilvr_d((v2i64)tmp3, (v2i64)tmp2);
380 tmp7 = (v2f64)__msa_ilvl_d((v2i64)tmp3, (v2i64)tmp2);
381 det1 = tmp6 - tmp7;
382 tmp6 = (v2f64)__msa_ilvr_d((v2i64)tmp5, (v2i64)tmp4);
383 tmp7 = (v2f64)__msa_ilvl_d((v2i64)tmp5, (v2i64)tmp4);
384 det2 = tmp6 - tmp7;
385
386 // Co-factors
387 tmp0 = mat0 * (v2f64)__msa_splati_d((v2i64)det0, 0);
388 tmp1 = mat0 * (v2f64)__msa_splati_d((v2i64)det0, 1);
389 tmp2 = mat0 * (v2f64)__msa_splati_d((v2i64)det1, 0);
390 tmp3 = mat2 * (v2f64)__msa_splati_d((v2i64)det0, 0);
391 tmp4 = mat2 * (v2f64)__msa_splati_d((v2i64)det1, 1);
392 tmp5 = mat2 * (v2f64)__msa_splati_d((v2i64)det2, 0);
393 tmp6 = mat4 * (v2f64)__msa_splati_d((v2i64)det0, 1);
394 tmp7 = mat4 * (v2f64)__msa_splati_d((v2i64)det1, 1);
395 tmp8 = mat4 * (v2f64)__msa_splati_d((v2i64)det2, 1);
396 tmp9 = mat6 * (v2f64)__msa_splati_d((v2i64)det1, 0);
397 tmp10 = mat6 * (v2f64)__msa_splati_d((v2i64)det2, 0);
398 tmp11 = mat6 * (v2f64)__msa_splati_d((v2i64)det2, 1);
399
400 tmp0 -= tmp7;
401 tmp1 -= tmp4;
402 tmp2 -= tmp5;
403 tmp3 -= tmp6;
404 tmp0 += tmp10;
405 tmp1 += tmp11;
406 tmp2 += tmp8;
407 tmp3 += tmp9;
408
409 // Multiply with 1/det
410 tmp0 *= rdet;
411 tmp1 *= rdet;
412 tmp2 *= rdet;
413 tmp3 *= rdet;
414
415 // Inverse: Upper half
416 result[0][0] = tmp3[1];
417 result[0][1] = -tmp0[1];
418 result[0][2] = tmp1[1];
419 result[0][3] = -tmp2[1];
420 result[1][0] = -tmp3[0];
421 result[1][1] = tmp0[0];
422 result[1][2] = -tmp1[0];
423 result[1][3] = tmp2[0];
424 // Left half
425 rev2 = SLDI_D(mat2, mat2, 8); // m13 m12
426 rev4 = SLDI_D(mat4, mat4, 8); // m23 m22
427 rev6 = SLDI_D(mat6, mat6, 8); // m33 m32
428
429 // 2*2 Determinants
430 // for A00 & A01
431 tmp0 = mat4 * rev6;
432 tmp1 = mat2 * rev6;
433 tmp2 = mat2 * rev4;
434 // for A10 & A11
435 tmp3 = mat0 * rev6;
436 tmp4 = mat0 * rev4;
437 // for A20 & A21
438 tmp5 = mat0 * rev2;
439 // for A30 & A31
440 tmp6 = (v2f64)__msa_ilvr_d((v2i64)tmp1, (v2i64)tmp0);
441 tmp7 = (v2f64)__msa_ilvl_d((v2i64)tmp1, (v2i64)tmp0);
442 det0 = tmp6 - tmp7;
443 tmp6 = (v2f64)__msa_ilvr_d((v2i64)tmp3, (v2i64)tmp2);
444 tmp7 = (v2f64)__msa_ilvl_d((v2i64)tmp3, (v2i64)tmp2);
445 det1 = tmp6 - tmp7;
446 tmp6 = (v2f64)__msa_ilvr_d((v2i64)tmp5, (v2i64)tmp4);
447 tmp7 = (v2f64)__msa_ilvl_d((v2i64)tmp5, (v2i64)tmp4);
448 det2 = tmp6 - tmp7;
449
450 // Co-factors
451 tmp0 = mat3 * (v2f64)__msa_splati_d((v2i64)det0, 0);
452 tmp1 = mat1 * (v2f64)__msa_splati_d((v2i64)det0, 1);
453 tmp2 = mat1 * (v2f64)__msa_splati_d((v2i64)det0, 0);
454 tmp3 = mat1 * (v2f64)__msa_splati_d((v2i64)det1, 0);
455 tmp4 = mat3 * (v2f64)__msa_splati_d((v2i64)det1, 1);
456 tmp5 = mat3 * (v2f64)__msa_splati_d((v2i64)det2, 0);
457 tmp6 = mat5 * (v2f64)__msa_splati_d((v2i64)det0, 1);
458 tmp7 = mat5 * (v2f64)__msa_splati_d((v2i64)det1, 1);
459 tmp8 = mat5 * (v2f64)__msa_splati_d((v2i64)det2, 1);
460 tmp9 = mat7 * (v2f64)__msa_splati_d((v2i64)det1, 0);
461 tmp10 = mat7 * (v2f64)__msa_splati_d((v2i64)det2, 0);
462 tmp11 = mat7 * (v2f64)__msa_splati_d((v2i64)det2, 1);
463 tmp0 -= tmp6;
464 tmp1 -= tmp4;
465 tmp2 -= tmp7;
466 tmp3 -= tmp5;
467 tmp0 += tmp9;
468 tmp1 += tmp11;
469 tmp2 += tmp10;
470 tmp3 += tmp8;
471
472 // Multiply with 1/det
473 tmp0 *= rdet;
474 tmp1 *= rdet;
475 tmp2 *= rdet;
476 tmp3 *= rdet;
477
478 // Inverse: Lower half
479 result[2][0] = tmp0[1];
480 result[2][1] = -tmp2[1];
481 result[2][2] = tmp1[1];
482 result[2][3] = -tmp3[1];
483 result[3][0] = -tmp0[0];
484 result[3][1] = tmp2[0];
485 result[3][2] = -tmp1[0];
486 result[3][3] = tmp3[0];
487 #else
488 // Calculate the adjoint matrix
489 Adjoint(matrix, result);
490
491 double rdet = 1 / det;
492
493 // Scale the adjoint matrix to get the inverse
494 for (int i = 0; i < 4; i++)
495 for (int j = 0; j < 4; j++)
496 result[i][j] = result[i][j] * rdet;
497 #endif
498 return true;
499 }
500
501 // End of code adapted from Matrix Inversion by Richard Carling
502
503 // Perform a decomposition on the passed matrix, return false if unsuccessful
504 // From Graphics Gems: unmatrix.c
505
506 // Transpose rotation portion of matrix a, return b
TransposeMatrix4(const TransformationMatrix::Matrix4 & a,TransformationMatrix::Matrix4 & b)507 static void TransposeMatrix4(const TransformationMatrix::Matrix4& a,
508 TransformationMatrix::Matrix4& b) {
509 for (int i = 0; i < 4; i++)
510 for (int j = 0; j < 4; j++)
511 b[i][j] = a[j][i];
512 }
513
514 // Multiply a homogeneous point by a matrix and return the transformed point
V4MulPointByMatrix(const Vector4 p,const TransformationMatrix::Matrix4 & m,Vector4 result)515 static void V4MulPointByMatrix(const Vector4 p,
516 const TransformationMatrix::Matrix4& m,
517 Vector4 result) {
518 result[0] =
519 (p[0] * m[0][0]) + (p[1] * m[1][0]) + (p[2] * m[2][0]) + (p[3] * m[3][0]);
520 result[1] =
521 (p[0] * m[0][1]) + (p[1] * m[1][1]) + (p[2] * m[2][1]) + (p[3] * m[3][1]);
522 result[2] =
523 (p[0] * m[0][2]) + (p[1] * m[1][2]) + (p[2] * m[2][2]) + (p[3] * m[3][2]);
524 result[3] =
525 (p[0] * m[0][3]) + (p[1] * m[1][3]) + (p[2] * m[2][3]) + (p[3] * m[3][3]);
526 }
527
V3Length(Vector3 a)528 static double V3Length(Vector3 a) {
529 return std::sqrt((a[0] * a[0]) + (a[1] * a[1]) + (a[2] * a[2]));
530 }
531
V3Scale(Vector3 v,double desired_length)532 static void V3Scale(Vector3 v, double desired_length) {
533 double len = V3Length(v);
534 if (len != 0) {
535 double l = desired_length / len;
536 v[0] *= l;
537 v[1] *= l;
538 v[2] *= l;
539 }
540 }
541
V3Dot(const Vector3 a,const Vector3 b)542 static double V3Dot(const Vector3 a, const Vector3 b) {
543 return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]);
544 }
545
546 // Make a linear combination of two vectors and return the result.
547 // result = (a * ascl) + (b * bscl)
V3Combine(const Vector3 a,const Vector3 b,Vector3 result,double ascl,double bscl)548 static void V3Combine(const Vector3 a,
549 const Vector3 b,
550 Vector3 result,
551 double ascl,
552 double bscl) {
553 result[0] = (ascl * a[0]) + (bscl * b[0]);
554 result[1] = (ascl * a[1]) + (bscl * b[1]);
555 result[2] = (ascl * a[2]) + (bscl * b[2]);
556 }
557
558 // Return the cross product result = a cross b */
V3Cross(const Vector3 a,const Vector3 b,Vector3 result)559 static void V3Cross(const Vector3 a, const Vector3 b, Vector3 result) {
560 result[0] = (a[1] * b[2]) - (a[2] * b[1]);
561 result[1] = (a[2] * b[0]) - (a[0] * b[2]);
562 result[2] = (a[0] * b[1]) - (a[1] * b[0]);
563 }
564
565 // TODO(crbug/937296): This implementation is virtually identical to the
566 // implementation in ui/gfx/transform_util with the main difference being
567 // the representation of the underlying matrix. These implementations should be
568 // consolidated.
Decompose(const TransformationMatrix::Matrix4 & mat,TransformationMatrix::DecomposedType & result)569 static bool Decompose(const TransformationMatrix::Matrix4& mat,
570 TransformationMatrix::DecomposedType& result) {
571 // https://www.w3.org/TR/css-transforms-2/#decomposing-a-3d-matrix.
572
573 TransformationMatrix::Matrix4 local_matrix;
574 memcpy(&local_matrix, &mat, sizeof(TransformationMatrix::Matrix4));
575
576 // Normalize the matrix.
577 if (local_matrix[3][3] == 0)
578 return false;
579
580 int i, j;
581 for (i = 0; i < 4; i++)
582 for (j = 0; j < 4; j++)
583 local_matrix[i][j] /= local_matrix[3][3];
584
585 // perspectiveMatrix is used to solve for perspective, but it also provides
586 // an easy way to test for singularity of the upper 3x3 component.
587 TransformationMatrix::Matrix4 perspective_matrix;
588 memcpy(&perspective_matrix, &local_matrix,
589 sizeof(TransformationMatrix::Matrix4));
590 for (i = 0; i < 3; i++)
591 perspective_matrix[i][3] = 0;
592 perspective_matrix[3][3] = 1;
593
594 if (Determinant4x4(perspective_matrix) == 0)
595 return false;
596
597 // First, isolate perspective. This is the messiest.
598 if (local_matrix[0][3] != 0 || local_matrix[1][3] != 0 ||
599 local_matrix[2][3] != 0) {
600 // rightHandSide is the right hand side of the equation.
601 Vector4 right_hand_side;
602 right_hand_side[0] = local_matrix[0][3];
603 right_hand_side[1] = local_matrix[1][3];
604 right_hand_side[2] = local_matrix[2][3];
605 right_hand_side[3] = local_matrix[3][3];
606
607 // Solve the equation by inverting perspectiveMatrix and multiplying
608 // rightHandSide by the inverse. (This is the easiest way, not
609 // necessarily the best.)
610 TransformationMatrix::Matrix4 inverse_perspective_matrix,
611 transposed_inverse_perspective_matrix;
612 if (!Inverse(perspective_matrix, inverse_perspective_matrix))
613 return false;
614 TransposeMatrix4(inverse_perspective_matrix,
615 transposed_inverse_perspective_matrix);
616
617 Vector4 perspective_point;
618 V4MulPointByMatrix(right_hand_side, transposed_inverse_perspective_matrix,
619 perspective_point);
620
621 result.perspective_x = perspective_point[0];
622 result.perspective_y = perspective_point[1];
623 result.perspective_z = perspective_point[2];
624 result.perspective_w = perspective_point[3];
625
626 // Clear the perspective partition
627 local_matrix[0][3] = local_matrix[1][3] = local_matrix[2][3] = 0;
628 local_matrix[3][3] = 1;
629 } else {
630 // No perspective.
631 result.perspective_x = result.perspective_y = result.perspective_z = 0;
632 result.perspective_w = 1;
633 }
634
635 // Next take care of translation (easy).
636 result.translate_x = local_matrix[3][0];
637 local_matrix[3][0] = 0;
638 result.translate_y = local_matrix[3][1];
639 local_matrix[3][1] = 0;
640 result.translate_z = local_matrix[3][2];
641 local_matrix[3][2] = 0;
642
643 // Vector4 type and functions need to be added to the common set.
644 // Note: Deviating from the spec in terms of variable naming. The matrix is
645 // stored on column major order and not row major. Using the variable 'row'
646 // instead of 'column' in the spec pseudocode has been the source of
647 // confusion, specifically in sorting out rotations.
648 Vector3 column[3], pdum3;
649
650 // Now get scale and shear.
651 for (i = 0; i < 3; i++) {
652 column[i][0] = local_matrix[i][0];
653 column[i][1] = local_matrix[i][1];
654 column[i][2] = local_matrix[i][2];
655 }
656
657 // Compute X scale factor and normalize the first column.
658 result.scale_x = V3Length(column[0]);
659 V3Scale(column[0], 1.0);
660
661 // Compute XY shear factor and make 2nd row orthogonal to 1st.
662 result.skew_xy = V3Dot(column[0], column[1]);
663 V3Combine(column[1], column[0], column[1], 1.0, -result.skew_xy);
664
665 // Now, compute Y scale and normalize 2nd column.
666 result.scale_y = V3Length(column[1]);
667 V3Scale(column[1], 1.0);
668 result.skew_xy /= result.scale_y;
669
670 // Compute XZ and YZ shears, and orthogonalize the 3rd column.
671 result.skew_xz = V3Dot(column[0], column[2]);
672 V3Combine(column[2], column[0], column[2], 1.0, -result.skew_xz);
673 result.skew_yz = V3Dot(column[1], column[2]);
674 V3Combine(column[2], column[1], column[2], 1.0, -result.skew_yz);
675
676 // Next, get Z scale and normalize the 3rd column.
677 result.scale_z = V3Length(column[2]);
678 V3Scale(column[2], 1.0);
679 result.skew_xz /= result.scale_z;
680 result.skew_yz /= result.scale_z;
681
682 // At this point, the matrix (in column[]) is orthonormal.
683 // Check for a coordinate system flip. If the determinant
684 // is -1, then negate the matrix and the scaling factors.
685 V3Cross(column[1], column[2], pdum3);
686 if (V3Dot(column[0], pdum3) < 0) {
687 // Note that flipping only one of the 3 scaling factors would also flip
688 // the sign of the determinant. By flipping all 3, we turn a 2D matrix
689 // interpolation into a 3D interpolation.
690 result.scale_x *= -1;
691 result.scale_y *= -1;
692 result.scale_z *= -1;
693
694 for (i = 0; i < 3; i++) {
695 column[i][0] *= -1;
696 column[i][1] *= -1;
697 column[i][2] *= -1;
698 }
699 }
700
701 // Lastly, compute the quaternions.
702 // See https://en.wikipedia.org/wiki/Rotation_matrix#Quaternion.
703 // Note: deviating from spec (http://www.w3.org/TR/css3-transforms/)
704 // which has a degenerate case when the trace (t) of the orthonormal matrix
705 // (Q) approaches -1. In the Wikipedia article, Q_ij is indexing on row then
706 // column. Thus, Q_ij = column[j][i].
707
708 // The following are equivalent represnetations of the rotation matrix:
709 //
710 // Axis-angle form:
711 //
712 // [ c+(1-c)x^2 (1-c)xy-sz (1-c)xz+sy ] c = cos theta
713 // R = [ (1-c)xy+sz c+(1-c)y^2 (1-c)yz-sx ] s = sin theta
714 // [ (1-c)xz-sy (1-c)yz+sx c+(1-c)z^2 ] [x,y,z] = axis or rotation
715 //
716 // The sum of the diagonal elements (trace) is a simple function of the cosine
717 // of the angle. The w component of the quaternion is cos(theta/2), and we
718 // make use of the double angle formula to directly compute w from the
719 // trace. Differences between pairs of skew symmetric elements in this matrix
720 // isolate the remaining components. Since w can be zero (also numerically
721 // unstable if near zero), we cannot rely solely on this approach to compute
722 // the quaternion components.
723 //
724 // Quaternion form:
725 //
726 // [ 1-2(y^2+z^2) 2(xy-zw) 2(xz+yw) ]
727 // r = [ 2(xy+zw) 1-2(x^2+z^2) 2(yz-xw) ] q = (x,y,y,w)
728 // [ 2(xz-yw) 2(yz+xw) 1-2(x^2+y^2) ]
729 //
730 // Different linear combinations of the diagonal elements isolates x, y or z.
731 // Sums or differences between skew symmetric elements isolate the remainder.
732
733 double r, s, t, x, y, z, w;
734
735 t = column[0][0] + column[1][1] + column[2][2]; // trace of Q
736
737 // https://en.wikipedia.org/wiki/Rotation_matrix#Quaternion
738 if (1 + t > 0.001) {
739 // Numerically stable as long as 1+t is not close to zero. Otherwise use the
740 // diagonal element with the greatest value to compute the quaternions.
741 r = std::sqrt(1.0 + t);
742 s = 0.5 / r;
743 w = 0.5 * r;
744 x = (column[1][2] - column[2][1]) * s;
745 y = (column[2][0] - column[0][2]) * s;
746 z = (column[0][1] - column[1][0]) * s;
747 } else if (column[0][0] > column[1][1] && column[0][0] > column[2][2]) {
748 // Q_xx is largest.
749 r = std::sqrt(1.0 + column[0][0] - column[1][1] - column[2][2]);
750 s = 0.5 / r;
751 x = 0.5 * r;
752 y = (column[1][0] - column[0][1]) * s;
753 z = (column[2][0] + column[0][2]) * s;
754 w = (column[1][2] - column[2][1]) * s;
755 } else if (column[1][1] > column[2][2]) {
756 // Q_yy is largest.
757 r = std::sqrt(1.0 - column[0][0] + column[1][1] - column[2][2]);
758 s = 0.5 / r;
759 x = (column[1][0] + column[0][1]) * s;
760 y = 0.5 * r;
761 z = (column[2][1] + column[1][2]) * s;
762 w = (column[2][0] - column[0][2]) * s;
763 } else {
764 // Q_zz is largest.
765 r = std::sqrt(1.0 - column[0][0] - column[1][1] + column[2][2]);
766 s = 0.5 / r;
767 x = (column[2][0] + column[0][2]) * s;
768 y = (column[2][1] + column[1][2]) * s;
769 z = 0.5 * r;
770 w = (column[0][1] - column[1][0]) * s;
771 }
772
773 result.quaternion_x = x;
774 result.quaternion_y = y;
775 result.quaternion_z = z;
776 result.quaternion_w = w;
777
778 return true;
779 }
780
ToQuaterion(const TransformationMatrix::DecomposedType & decomp)781 Quaternion ToQuaterion(const TransformationMatrix::DecomposedType& decomp) {
782 return Quaternion(decomp.quaternion_x, decomp.quaternion_y,
783 decomp.quaternion_z, decomp.quaternion_w);
784 }
785
Slerp(TransformationMatrix::DecomposedType & from_decomp,const TransformationMatrix::DecomposedType & to_decomp,double progress)786 void Slerp(TransformationMatrix::DecomposedType& from_decomp,
787 const TransformationMatrix::DecomposedType& to_decomp,
788 double progress) {
789 Quaternion qa = ToQuaterion(from_decomp);
790 Quaternion qb = ToQuaterion(to_decomp);
791 Quaternion qc = qa.Slerp(qb, progress);
792 from_decomp.quaternion_x = qc.x();
793 from_decomp.quaternion_y = qc.y();
794 from_decomp.quaternion_z = qc.z();
795 from_decomp.quaternion_w = qc.w();
796 }
797
798 // End of Supporting Math Functions
799
TransformationMatrix(const AffineTransform & t)800 TransformationMatrix::TransformationMatrix(const AffineTransform& t) {
801 SetMatrix(t.A(), t.B(), t.C(), t.D(), t.E(), t.F());
802 }
803
Scale(double s)804 TransformationMatrix& TransformationMatrix::Scale(double s) {
805 return ScaleNonUniform(s, s);
806 }
807
ProjectPoint(const FloatPoint & p,bool * clamped) const808 FloatPoint TransformationMatrix::ProjectPoint(const FloatPoint& p,
809 bool* clamped) const {
810 // This is basically raytracing. We have a point in the destination
811 // plane with z=0, and we cast a ray parallel to the z-axis from that
812 // point to find the z-position at which it intersects the z=0 plane
813 // with the transform applied. Once we have that point we apply the
814 // inverse transform to find the corresponding point in the source
815 // space.
816 //
817 // Given a plane with normal Pn, and a ray starting at point R0 and
818 // with direction defined by the vector Rd, we can find the
819 // intersection point as a distance d from R0 in units of Rd by:
820 //
821 // d = -dot (Pn', R0) / dot (Pn', Rd)
822 if (clamped)
823 *clamped = false;
824
825 if (M33() == 0) {
826 // In this case, the projection plane is parallel to the ray we are trying
827 // to trace, and there is no well-defined value for the projection.
828 return FloatPoint();
829 }
830
831 double x = p.X();
832 double y = p.Y();
833 double z = -(M13() * x + M23() * y + M43()) / M33();
834
835 // FIXME: use multVecMatrix()
836 double out_x = x * M11() + y * M21() + z * M31() + M41();
837 double out_y = x * M12() + y * M22() + z * M32() + M42();
838
839 double w = x * M14() + y * M24() + z * M34() + M44();
840 if (w <= 0) {
841 // Using int max causes overflow when other code uses the projected point.
842 // To represent infinity yet reduce the risk of overflow, we use a large but
843 // not-too-large number here when clamping.
844 const int kLargeNumber = 100000000 / kFixedPointDenominator;
845 out_x = copysign(kLargeNumber, out_x);
846 out_y = copysign(kLargeNumber, out_y);
847 if (clamped)
848 *clamped = true;
849 } else if (w != 1) {
850 out_x /= w;
851 out_y /= w;
852 }
853
854 return FloatPoint(static_cast<float>(out_x), static_cast<float>(out_y));
855 }
856
ProjectQuad(const FloatQuad & q) const857 FloatQuad TransformationMatrix::ProjectQuad(const FloatQuad& q) const {
858 FloatQuad projected_quad;
859
860 bool clamped1 = false;
861 bool clamped2 = false;
862 bool clamped3 = false;
863 bool clamped4 = false;
864
865 projected_quad.SetP1(ProjectPoint(q.P1(), &clamped1));
866 projected_quad.SetP2(ProjectPoint(q.P2(), &clamped2));
867 projected_quad.SetP3(ProjectPoint(q.P3(), &clamped3));
868 projected_quad.SetP4(ProjectPoint(q.P4(), &clamped4));
869
870 // If all points on the quad had w < 0, then the entire quad would not be
871 // visible to the projected surface.
872 bool everything_was_clipped = clamped1 && clamped2 && clamped3 && clamped4;
873 if (everything_was_clipped)
874 return FloatQuad();
875
876 return projected_quad;
877 }
878
ClampEdgeValue(float f)879 static float ClampEdgeValue(float f) {
880 DCHECK(!std::isnan(f));
881 return clampTo(f, (-LayoutUnit::Max() / 2).ToFloat(),
882 (LayoutUnit::Max() / 2).ToFloat());
883 }
884
ClampedBoundsOfProjectedQuad(const FloatQuad & q) const885 LayoutRect TransformationMatrix::ClampedBoundsOfProjectedQuad(
886 const FloatQuad& q) const {
887 FloatRect mapped_quad_bounds = ProjectQuad(q).BoundingBox();
888
889 float left = ClampEdgeValue(floorf(mapped_quad_bounds.X()));
890 float top = ClampEdgeValue(floorf(mapped_quad_bounds.Y()));
891
892 float right;
893 if (std::isinf(mapped_quad_bounds.X()) &&
894 std::isinf(mapped_quad_bounds.Width()))
895 right = (LayoutUnit::Max() / 2).ToFloat();
896 else
897 right = ClampEdgeValue(ceilf(mapped_quad_bounds.MaxX()));
898
899 float bottom;
900 if (std::isinf(mapped_quad_bounds.Y()) &&
901 std::isinf(mapped_quad_bounds.Height()))
902 bottom = (LayoutUnit::Max() / 2).ToFloat();
903 else
904 bottom = ClampEdgeValue(ceilf(mapped_quad_bounds.MaxY()));
905
906 return LayoutRect(LayoutUnit::Clamp(left), LayoutUnit::Clamp(top),
907 LayoutUnit::Clamp(right - left),
908 LayoutUnit::Clamp(bottom - top));
909 }
910
TransformBox(FloatBox & box) const911 void TransformationMatrix::TransformBox(FloatBox& box) const {
912 FloatBox bounds;
913 bool first_point = true;
914 for (size_t i = 0; i < 2; ++i) {
915 for (size_t j = 0; j < 2; ++j) {
916 for (size_t k = 0; k < 2; ++k) {
917 FloatPoint3D point(box.X(), box.Y(), box.Z());
918 point +=
919 FloatPoint3D(i * box.Width(), j * box.Height(), k * box.Depth());
920 point = MapPoint(point);
921 if (first_point) {
922 bounds.SetOrigin(point);
923 first_point = false;
924 } else {
925 bounds.ExpandTo(point);
926 }
927 }
928 }
929 }
930 box = bounds;
931 }
932
MapPoint(const FloatPoint & p) const933 FloatPoint TransformationMatrix::MapPoint(const FloatPoint& p) const {
934 if (IsIdentityOrTranslation())
935 return FloatPoint(p.X() + static_cast<float>(matrix_[3][0]),
936 p.Y() + static_cast<float>(matrix_[3][1]));
937
938 return InternalMapPoint(p);
939 }
940
MapPoint(const FloatPoint3D & p) const941 FloatPoint3D TransformationMatrix::MapPoint(const FloatPoint3D& p) const {
942 if (IsIdentityOrTranslation())
943 return FloatPoint3D(p.X() + static_cast<float>(matrix_[3][0]),
944 p.Y() + static_cast<float>(matrix_[3][1]),
945 p.Z() + static_cast<float>(matrix_[3][2]));
946
947 return InternalMapPoint(p);
948 }
949
MapRect(const IntRect & rect) const950 IntRect TransformationMatrix::MapRect(const IntRect& rect) const {
951 return EnclosingIntRect(MapRect(FloatRect(rect)));
952 }
953
MapRect(const LayoutRect & r) const954 LayoutRect TransformationMatrix::MapRect(const LayoutRect& r) const {
955 return EnclosingLayoutRect(MapRect(FloatRect(r)));
956 }
957
MapRect(const FloatRect & r) const958 FloatRect TransformationMatrix::MapRect(const FloatRect& r) const {
959 if (IsIdentityOrTranslation()) {
960 FloatRect mapped_rect(r);
961 mapped_rect.Move(static_cast<float>(matrix_[3][0]),
962 static_cast<float>(matrix_[3][1]));
963 return mapped_rect;
964 }
965
966 FloatQuad result;
967
968 float max_x = r.MaxX();
969 float max_y = r.MaxY();
970 result.SetP1(InternalMapPoint(FloatPoint(r.X(), r.Y())));
971 result.SetP2(InternalMapPoint(FloatPoint(max_x, r.Y())));
972 result.SetP3(InternalMapPoint(FloatPoint(max_x, max_y)));
973 result.SetP4(InternalMapPoint(FloatPoint(r.X(), max_y)));
974
975 return result.BoundingBox();
976 }
977
MapQuad(const FloatQuad & q) const978 FloatQuad TransformationMatrix::MapQuad(const FloatQuad& q) const {
979 if (IsIdentityOrTranslation()) {
980 FloatQuad mapped_quad(q);
981 mapped_quad.Move(static_cast<float>(matrix_[3][0]),
982 static_cast<float>(matrix_[3][1]));
983 return mapped_quad;
984 }
985
986 FloatQuad result;
987 result.SetP1(InternalMapPoint(q.P1()));
988 result.SetP2(InternalMapPoint(q.P2()));
989 result.SetP3(InternalMapPoint(q.P3()));
990 result.SetP4(InternalMapPoint(q.P4()));
991 return result;
992 }
993
ScaleNonUniform(double sx,double sy)994 TransformationMatrix& TransformationMatrix::ScaleNonUniform(double sx,
995 double sy) {
996 matrix_[0][0] *= sx;
997 matrix_[0][1] *= sx;
998 matrix_[0][2] *= sx;
999 matrix_[0][3] *= sx;
1000
1001 matrix_[1][0] *= sy;
1002 matrix_[1][1] *= sy;
1003 matrix_[1][2] *= sy;
1004 matrix_[1][3] *= sy;
1005 return *this;
1006 }
1007
Scale3d(double sx,double sy,double sz)1008 TransformationMatrix& TransformationMatrix::Scale3d(double sx,
1009 double sy,
1010 double sz) {
1011 ScaleNonUniform(sx, sy);
1012
1013 matrix_[2][0] *= sz;
1014 matrix_[2][1] *= sz;
1015 matrix_[2][2] *= sz;
1016 matrix_[2][3] *= sz;
1017 return *this;
1018 }
1019
Rotate3d(const Rotation & rotation)1020 TransformationMatrix& TransformationMatrix::Rotate3d(const Rotation& rotation) {
1021 return Rotate3d(rotation.axis.X(), rotation.axis.Y(), rotation.axis.Z(),
1022 rotation.angle);
1023 }
1024
Rotate3d(double x,double y,double z,double angle)1025 TransformationMatrix& TransformationMatrix::Rotate3d(double x,
1026 double y,
1027 double z,
1028 double angle) {
1029 // Normalize the axis of rotation
1030 double length = std::sqrt(x * x + y * y + z * z);
1031 if (length == 0) {
1032 // A direction vector that cannot be normalized, such as [0, 0, 0], will
1033 // cause the rotation to not be applied.
1034 return *this;
1035 } else if (length != 1) {
1036 x /= length;
1037 y /= length;
1038 z /= length;
1039 }
1040
1041 // Angles are in degrees. Switch to radians.
1042 angle = deg2rad(angle);
1043
1044 double sin_theta = std::sin(angle);
1045 double cos_theta = std::cos(angle);
1046
1047 TransformationMatrix mat;
1048
1049 // Optimize cases where the axis is along a major axis
1050 // Since we've already normalized the vector we don't need to check that the
1051 // other two dimensions are zero
1052 if (x == 1.0) {
1053 mat.matrix_[0][0] = 1.0;
1054 mat.matrix_[0][1] = 0.0;
1055 mat.matrix_[0][2] = 0.0;
1056 mat.matrix_[1][0] = 0.0;
1057 mat.matrix_[1][1] = cos_theta;
1058 mat.matrix_[1][2] = sin_theta;
1059 mat.matrix_[2][0] = 0.0;
1060 mat.matrix_[2][1] = -sin_theta;
1061 mat.matrix_[2][2] = cos_theta;
1062 mat.matrix_[0][3] = mat.matrix_[1][3] = mat.matrix_[2][3] = 0.0;
1063 mat.matrix_[3][0] = mat.matrix_[3][1] = mat.matrix_[3][2] = 0.0;
1064 mat.matrix_[3][3] = 1.0;
1065 } else if (y == 1.0) {
1066 mat.matrix_[0][0] = cos_theta;
1067 mat.matrix_[0][1] = 0.0;
1068 mat.matrix_[0][2] = -sin_theta;
1069 mat.matrix_[1][0] = 0.0;
1070 mat.matrix_[1][1] = 1.0;
1071 mat.matrix_[1][2] = 0.0;
1072 mat.matrix_[2][0] = sin_theta;
1073 mat.matrix_[2][1] = 0.0;
1074 mat.matrix_[2][2] = cos_theta;
1075 mat.matrix_[0][3] = mat.matrix_[1][3] = mat.matrix_[2][3] = 0.0;
1076 mat.matrix_[3][0] = mat.matrix_[3][1] = mat.matrix_[3][2] = 0.0;
1077 mat.matrix_[3][3] = 1.0;
1078 } else if (z == 1.0) {
1079 mat.matrix_[0][0] = cos_theta;
1080 mat.matrix_[0][1] = sin_theta;
1081 mat.matrix_[0][2] = 0.0;
1082 mat.matrix_[1][0] = -sin_theta;
1083 mat.matrix_[1][1] = cos_theta;
1084 mat.matrix_[1][2] = 0.0;
1085 mat.matrix_[2][0] = 0.0;
1086 mat.matrix_[2][1] = 0.0;
1087 mat.matrix_[2][2] = 1.0;
1088 mat.matrix_[0][3] = mat.matrix_[1][3] = mat.matrix_[2][3] = 0.0;
1089 mat.matrix_[3][0] = mat.matrix_[3][1] = mat.matrix_[3][2] = 0.0;
1090 mat.matrix_[3][3] = 1.0;
1091 } else {
1092 // This case is the rotation about an arbitrary unit vector.
1093 //
1094 // Formula is adapted from Wikipedia article on Rotation matrix,
1095 // http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle
1096 //
1097 // An alternate resource with the same matrix:
1098 // http://www.fastgraph.com/makegames/3drotation/
1099 //
1100 double one_minus_cos_theta = 1 - cos_theta;
1101 mat.matrix_[0][0] = cos_theta + x * x * one_minus_cos_theta;
1102 mat.matrix_[0][1] = y * x * one_minus_cos_theta + z * sin_theta;
1103 mat.matrix_[0][2] = z * x * one_minus_cos_theta - y * sin_theta;
1104 mat.matrix_[1][0] = x * y * one_minus_cos_theta - z * sin_theta;
1105 mat.matrix_[1][1] = cos_theta + y * y * one_minus_cos_theta;
1106 mat.matrix_[1][2] = z * y * one_minus_cos_theta + x * sin_theta;
1107 mat.matrix_[2][0] = x * z * one_minus_cos_theta + y * sin_theta;
1108 mat.matrix_[2][1] = y * z * one_minus_cos_theta - x * sin_theta;
1109 mat.matrix_[2][2] = cos_theta + z * z * one_minus_cos_theta;
1110 mat.matrix_[0][3] = mat.matrix_[1][3] = mat.matrix_[2][3] = 0.0;
1111 mat.matrix_[3][0] = mat.matrix_[3][1] = mat.matrix_[3][2] = 0.0;
1112 mat.matrix_[3][3] = 1.0;
1113 }
1114 Multiply(mat);
1115 return *this;
1116 }
1117
Rotate3d(double rx,double ry,double rz)1118 TransformationMatrix& TransformationMatrix::Rotate3d(double rx,
1119 double ry,
1120 double rz) {
1121 // Angles are in degrees. Switch to radians.
1122 rx = deg2rad(rx);
1123 ry = deg2rad(ry);
1124 rz = deg2rad(rz);
1125
1126 TransformationMatrix mat;
1127
1128 double sin_theta = std::sin(rz);
1129 double cos_theta = std::cos(rz);
1130
1131 mat.matrix_[0][0] = cos_theta;
1132 mat.matrix_[0][1] = sin_theta;
1133 mat.matrix_[0][2] = 0.0;
1134 mat.matrix_[1][0] = -sin_theta;
1135 mat.matrix_[1][1] = cos_theta;
1136 mat.matrix_[1][2] = 0.0;
1137 mat.matrix_[2][0] = 0.0;
1138 mat.matrix_[2][1] = 0.0;
1139 mat.matrix_[2][2] = 1.0;
1140 mat.matrix_[0][3] = mat.matrix_[1][3] = mat.matrix_[2][3] = 0.0;
1141 mat.matrix_[3][0] = mat.matrix_[3][1] = mat.matrix_[3][2] = 0.0;
1142 mat.matrix_[3][3] = 1.0;
1143
1144 TransformationMatrix rmat(mat);
1145
1146 sin_theta = std::sin(ry);
1147 cos_theta = std::cos(ry);
1148
1149 mat.matrix_[0][0] = cos_theta;
1150 mat.matrix_[0][1] = 0.0;
1151 mat.matrix_[0][2] = -sin_theta;
1152 mat.matrix_[1][0] = 0.0;
1153 mat.matrix_[1][1] = 1.0;
1154 mat.matrix_[1][2] = 0.0;
1155 mat.matrix_[2][0] = sin_theta;
1156 mat.matrix_[2][1] = 0.0;
1157 mat.matrix_[2][2] = cos_theta;
1158 mat.matrix_[0][3] = mat.matrix_[1][3] = mat.matrix_[2][3] = 0.0;
1159 mat.matrix_[3][0] = mat.matrix_[3][1] = mat.matrix_[3][2] = 0.0;
1160 mat.matrix_[3][3] = 1.0;
1161
1162 rmat.Multiply(mat);
1163
1164 sin_theta = std::sin(rx);
1165 cos_theta = std::cos(rx);
1166
1167 mat.matrix_[0][0] = 1.0;
1168 mat.matrix_[0][1] = 0.0;
1169 mat.matrix_[0][2] = 0.0;
1170 mat.matrix_[1][0] = 0.0;
1171 mat.matrix_[1][1] = cos_theta;
1172 mat.matrix_[1][2] = sin_theta;
1173 mat.matrix_[2][0] = 0.0;
1174 mat.matrix_[2][1] = -sin_theta;
1175 mat.matrix_[2][2] = cos_theta;
1176 mat.matrix_[0][3] = mat.matrix_[1][3] = mat.matrix_[2][3] = 0.0;
1177 mat.matrix_[3][0] = mat.matrix_[3][1] = mat.matrix_[3][2] = 0.0;
1178 mat.matrix_[3][3] = 1.0;
1179
1180 rmat.Multiply(mat);
1181
1182 Multiply(rmat);
1183 return *this;
1184 }
1185
Translate(double tx,double ty)1186 TransformationMatrix& TransformationMatrix::Translate(double tx, double ty) {
1187 matrix_[3][0] += tx * matrix_[0][0] + ty * matrix_[1][0];
1188 matrix_[3][1] += tx * matrix_[0][1] + ty * matrix_[1][1];
1189 matrix_[3][2] += tx * matrix_[0][2] + ty * matrix_[1][2];
1190 matrix_[3][3] += tx * matrix_[0][3] + ty * matrix_[1][3];
1191 return *this;
1192 }
1193
Translate3d(double tx,double ty,double tz)1194 TransformationMatrix& TransformationMatrix::Translate3d(double tx,
1195 double ty,
1196 double tz) {
1197 matrix_[3][0] += tx * matrix_[0][0] + ty * matrix_[1][0] + tz * matrix_[2][0];
1198 matrix_[3][1] += tx * matrix_[0][1] + ty * matrix_[1][1] + tz * matrix_[2][1];
1199 matrix_[3][2] += tx * matrix_[0][2] + ty * matrix_[1][2] + tz * matrix_[2][2];
1200 matrix_[3][3] += tx * matrix_[0][3] + ty * matrix_[1][3] + tz * matrix_[2][3];
1201 return *this;
1202 }
1203
PostTranslate(double tx,double ty)1204 TransformationMatrix& TransformationMatrix::PostTranslate(double tx,
1205 double ty) {
1206 if (tx != 0) {
1207 matrix_[0][0] += matrix_[0][3] * tx;
1208 matrix_[1][0] += matrix_[1][3] * tx;
1209 matrix_[2][0] += matrix_[2][3] * tx;
1210 matrix_[3][0] += matrix_[3][3] * tx;
1211 }
1212
1213 if (ty != 0) {
1214 matrix_[0][1] += matrix_[0][3] * ty;
1215 matrix_[1][1] += matrix_[1][3] * ty;
1216 matrix_[2][1] += matrix_[2][3] * ty;
1217 matrix_[3][1] += matrix_[3][3] * ty;
1218 }
1219
1220 return *this;
1221 }
1222
PostTranslate3d(double tx,double ty,double tz)1223 TransformationMatrix& TransformationMatrix::PostTranslate3d(double tx,
1224 double ty,
1225 double tz) {
1226 PostTranslate(tx, ty);
1227 if (tz != 0) {
1228 matrix_[0][2] += matrix_[0][3] * tz;
1229 matrix_[1][2] += matrix_[1][3] * tz;
1230 matrix_[2][2] += matrix_[2][3] * tz;
1231 matrix_[3][2] += matrix_[3][3] * tz;
1232 }
1233
1234 return *this;
1235 }
1236
Skew(double sx,double sy)1237 TransformationMatrix& TransformationMatrix::Skew(double sx, double sy) {
1238 // angles are in degrees. Switch to radians
1239 sx = deg2rad(sx);
1240 sy = deg2rad(sy);
1241
1242 TransformationMatrix mat;
1243 mat.matrix_[0][1] =
1244 std::tan(sy); // note that the y shear goes in the first row
1245 mat.matrix_[1][0] = std::tan(sx); // and the x shear in the second row
1246
1247 Multiply(mat);
1248 return *this;
1249 }
1250
ApplyPerspective(double p)1251 TransformationMatrix& TransformationMatrix::ApplyPerspective(double p) {
1252 TransformationMatrix mat;
1253 if (p != 0)
1254 mat.matrix_[2][3] = -1 / p;
1255
1256 Multiply(mat);
1257 return *this;
1258 }
1259
ApplyTransformOrigin(double x,double y,double z)1260 TransformationMatrix& TransformationMatrix::ApplyTransformOrigin(double x,
1261 double y,
1262 double z) {
1263 PostTranslate3d(x, y, z);
1264 Translate3d(-x, -y, -z);
1265 return *this;
1266 }
1267
Zoom(double zoom_factor)1268 TransformationMatrix& TransformationMatrix::Zoom(double zoom_factor) {
1269 matrix_[0][3] /= zoom_factor;
1270 matrix_[1][3] /= zoom_factor;
1271 matrix_[2][3] /= zoom_factor;
1272 matrix_[3][0] *= zoom_factor;
1273 matrix_[3][1] *= zoom_factor;
1274 matrix_[3][2] *= zoom_factor;
1275 return *this;
1276 }
1277
1278 // Calculates *this = *this * mat.
1279 // Note: As we are using the column vector convention, i.e. T * P,
1280 // (lhs * rhs) * P = lhs * (rhs * P)
1281 // That means from the perspective of the transformed object, the combined
1282 // transform is equal to applying the rhs(mat) first, then lhs(*this) second.
1283 // For example:
1284 // TransformationMatrix lhs; lhs.Rotate(90.f);
1285 // TransformationMatrix rhs; rhs.Translate(12.f, 34.f);
1286 // TransformationMatrix prod = lhs;
1287 // prod.Multiply(rhs);
1288 // lhs.MapPoint(rhs.MapPoint(p)) == prod.MapPoint(p)
1289 // Also 'prod' corresponds to CSS transform:rotateZ(90deg)translate(12px,34px).
Multiply(const TransformationMatrix & mat)1290 TransformationMatrix& TransformationMatrix::Multiply(
1291 const TransformationMatrix& mat) {
1292 #if defined(ARCH_CPU_ARM64)
1293 double* left_matrix = &(matrix_[0][0]);
1294 const double* right_matrix = &(mat.matrix_[0][0]);
1295 asm volatile(
1296 // Load this->matrix_ to v24 - v31.
1297 // Load mat.matrix_ to v16 - v23.
1298 // Result: *this = *this * mat
1299 // | v0 v2 v4 v6 | | v24 v26 v28 v30 | | v16 v18 v20 v22 |
1300 // | | = | | * | |
1301 // | v1 v3 v5 v7 | | v25 v27 v29 v31 | | v17 v19 v21 v23 |
1302 // | | | | | |
1303 "mov x9, %[left_matrix] \t\n"
1304 "ld1 {v16.2d - v19.2d}, [%[right_matrix]], 64 \t\n"
1305 "ld1 {v20.2d - v23.2d}, [%[right_matrix]] \t\n"
1306 "ld1 {v24.2d - v27.2d}, [%[left_matrix]], 64 \t\n"
1307 "ld1 {v28.2d - v31.2d}, [%[left_matrix]] \t\n"
1308
1309 "fmul v0.2d, v24.2d, v16.d[0] \t\n"
1310 "fmul v1.2d, v25.2d, v16.d[0] \t\n"
1311 "fmul v2.2d, v24.2d, v18.d[0] \t\n"
1312 "fmul v3.2d, v25.2d, v18.d[0] \t\n"
1313 "fmul v4.2d, v24.2d, v20.d[0] \t\n"
1314 "fmul v5.2d, v25.2d, v20.d[0] \t\n"
1315 "fmul v6.2d, v24.2d, v22.d[0] \t\n"
1316 "fmul v7.2d, v25.2d, v22.d[0] \t\n"
1317
1318 "fmla v0.2d, v26.2d, v16.d[1] \t\n"
1319 "fmla v1.2d, v27.2d, v16.d[1] \t\n"
1320 "fmla v2.2d, v26.2d, v18.d[1] \t\n"
1321 "fmla v3.2d, v27.2d, v18.d[1] \t\n"
1322 "fmla v4.2d, v26.2d, v20.d[1] \t\n"
1323 "fmla v5.2d, v27.2d, v20.d[1] \t\n"
1324 "fmla v6.2d, v26.2d, v22.d[1] \t\n"
1325 "fmla v7.2d, v27.2d, v22.d[1] \t\n"
1326
1327 "fmla v0.2d, v28.2d, v17.d[0] \t\n"
1328 "fmla v1.2d, v29.2d, v17.d[0] \t\n"
1329 "fmla v2.2d, v28.2d, v19.d[0] \t\n"
1330 "fmla v3.2d, v29.2d, v19.d[0] \t\n"
1331 "fmla v4.2d, v28.2d, v21.d[0] \t\n"
1332 "fmla v5.2d, v29.2d, v21.d[0] \t\n"
1333 "fmla v6.2d, v28.2d, v23.d[0] \t\n"
1334 "fmla v7.2d, v29.2d, v23.d[0] \t\n"
1335
1336 "fmla v0.2d, v30.2d, v17.d[1] \t\n"
1337 "fmla v1.2d, v31.2d, v17.d[1] \t\n"
1338 "fmla v2.2d, v30.2d, v19.d[1] \t\n"
1339 "fmla v3.2d, v31.2d, v19.d[1] \t\n"
1340 "fmla v4.2d, v30.2d, v21.d[1] \t\n"
1341 "fmla v5.2d, v31.2d, v21.d[1] \t\n"
1342 "fmla v6.2d, v30.2d, v23.d[1] \t\n"
1343 "fmla v7.2d, v31.2d, v23.d[1] \t\n"
1344
1345 "st1 {v0.2d - v3.2d}, [x9], 64 \t\n"
1346 "st1 {v4.2d - v7.2d}, [x9] \t\n"
1347 : [right_matrix] "+r"(right_matrix), [left_matrix] "+r"(left_matrix)
1348 :
1349 : "memory", "x9", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
1350 "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", "v0", "v1",
1351 "v2", "v3", "v4", "v5", "v6", "v7");
1352 #elif defined(HAVE_MIPS_MSA_INTRINSICS)
1353 v2f64 v_right_m0, v_right_m1, v_right_m2, v_right_m3, v_right_m4, v_right_m5,
1354 v_right_m6, v_right_m7;
1355 v2f64 v_left_m0, v_left_m1, v_left_m2, v_left_m3, v_left_m4, v_left_m5,
1356 v_left_m6, v_left_m7;
1357 v2f64 v_tmp_m0, v_tmp_m1, v_tmp_m2, v_tmp_m3;
1358
1359 v_left_m0 = LD_DP(&(matrix_[0][0]));
1360 v_left_m1 = LD_DP(&(matrix_[0][2]));
1361 v_left_m2 = LD_DP(&(matrix_[1][0]));
1362 v_left_m3 = LD_DP(&(matrix_[1][2]));
1363 v_left_m4 = LD_DP(&(matrix_[2][0]));
1364 v_left_m5 = LD_DP(&(matrix_[2][2]));
1365 v_left_m6 = LD_DP(&(matrix_[3][0]));
1366 v_left_m7 = LD_DP(&(matrix_[3][2]));
1367
1368 v_right_m0 = LD_DP(&(mat.matrix_[0][0]));
1369 v_right_m2 = LD_DP(&(mat.matrix_[0][2]));
1370 v_right_m4 = LD_DP(&(mat.matrix_[1][0]));
1371 v_right_m6 = LD_DP(&(mat.matrix_[1][2]));
1372
1373 v_right_m1 = (v2f64)__msa_splati_d((v2i64)v_right_m0, 1);
1374 v_right_m0 = (v2f64)__msa_splati_d((v2i64)v_right_m0, 0);
1375 v_right_m3 = (v2f64)__msa_splati_d((v2i64)v_right_m2, 1);
1376 v_right_m2 = (v2f64)__msa_splati_d((v2i64)v_right_m2, 0);
1377 v_right_m5 = (v2f64)__msa_splati_d((v2i64)v_right_m4, 1);
1378 v_right_m4 = (v2f64)__msa_splati_d((v2i64)v_right_m4, 0);
1379 v_right_m7 = (v2f64)__msa_splati_d((v2i64)v_right_m6, 1);
1380 v_right_m6 = (v2f64)__msa_splati_d((v2i64)v_right_m6, 0);
1381
1382 v_tmp_m0 = v_right_m0 * v_left_m0;
1383 v_tmp_m1 = v_right_m0 * v_left_m1;
1384 v_tmp_m0 += v_right_m1 * v_left_m2;
1385 v_tmp_m1 += v_right_m1 * v_left_m3;
1386 v_tmp_m0 += v_right_m2 * v_left_m4;
1387 v_tmp_m1 += v_right_m2 * v_left_m5;
1388 v_tmp_m0 += v_right_m3 * v_left_m6;
1389 v_tmp_m1 += v_right_m3 * v_left_m7;
1390
1391 v_tmp_m2 = v_right_m4 * v_left_m0;
1392 v_tmp_m3 = v_right_m4 * v_left_m1;
1393 v_tmp_m2 += v_right_m5 * v_left_m2;
1394 v_tmp_m3 += v_right_m5 * v_left_m3;
1395 v_tmp_m2 += v_right_m6 * v_left_m4;
1396 v_tmp_m3 += v_right_m6 * v_left_m5;
1397 v_tmp_m2 += v_right_m7 * v_left_m6;
1398 v_tmp_m3 += v_right_m7 * v_left_m7;
1399
1400 v_right_m0 = LD_DP(&(mat.matrix_[2][0]));
1401 v_right_m2 = LD_DP(&(mat.matrix_[2][2]));
1402 v_right_m4 = LD_DP(&(mat.matrix_[3][0]));
1403 v_right_m6 = LD_DP(&(mat.matrix_[3][2]));
1404
1405 ST_DP(v_tmp_m0, &(matrix_[0][0]));
1406 ST_DP(v_tmp_m1, &(matrix_[0][2]));
1407 ST_DP(v_tmp_m2, &(matrix_[1][0]));
1408 ST_DP(v_tmp_m3, &(matrix_[1][2]));
1409
1410 v_right_m1 = (v2f64)__msa_splati_d((v2i64)v_right_m0, 1);
1411 v_right_m0 = (v2f64)__msa_splati_d((v2i64)v_right_m0, 0);
1412 v_right_m3 = (v2f64)__msa_splati_d((v2i64)v_right_m2, 1);
1413 v_right_m2 = (v2f64)__msa_splati_d((v2i64)v_right_m2, 0);
1414 v_right_m5 = (v2f64)__msa_splati_d((v2i64)v_right_m4, 1);
1415 v_right_m4 = (v2f64)__msa_splati_d((v2i64)v_right_m4, 0);
1416 v_right_m7 = (v2f64)__msa_splati_d((v2i64)v_right_m6, 1);
1417 v_right_m6 = (v2f64)__msa_splati_d((v2i64)v_right_m6, 0);
1418
1419 v_tmp_m0 = v_right_m0 * v_left_m0;
1420 v_tmp_m1 = v_right_m0 * v_left_m1;
1421 v_tmp_m0 += v_right_m1 * v_left_m2;
1422 v_tmp_m1 += v_right_m1 * v_left_m3;
1423 v_tmp_m0 += v_right_m2 * v_left_m4;
1424 v_tmp_m1 += v_right_m2 * v_left_m5;
1425 v_tmp_m0 += v_right_m3 * v_left_m6;
1426 v_tmp_m1 += v_right_m3 * v_left_m7;
1427
1428 v_tmp_m2 = v_right_m4 * v_left_m0;
1429 v_tmp_m3 = v_right_m4 * v_left_m1;
1430 v_tmp_m2 += v_right_m5 * v_left_m2;
1431 v_tmp_m3 += v_right_m5 * v_left_m3;
1432 v_tmp_m2 += v_right_m6 * v_left_m4;
1433 v_tmp_m3 += v_right_m6 * v_left_m5;
1434 v_tmp_m2 += v_right_m7 * v_left_m6;
1435 v_tmp_m3 += v_right_m7 * v_left_m7;
1436
1437 ST_DP(v_tmp_m0, &(matrix_[2][0]));
1438 ST_DP(v_tmp_m1, &(matrix_[2][2]));
1439 ST_DP(v_tmp_m2, &(matrix_[3][0]));
1440 ST_DP(v_tmp_m3, &(matrix_[3][2]));
1441 #elif defined(ARCH_CPU_X86_64)
1442 // x86_64 has 16 XMM registers which is enough to do the multiplication fully
1443 // in registers.
1444 __m128d matrix_block_a = _mm_loadu_pd(&(matrix_[0][0]));
1445 __m128d matrix_block_c = _mm_loadu_pd(&(matrix_[1][0]));
1446 __m128d matrix_block_e = _mm_loadu_pd(&(matrix_[2][0]));
1447 __m128d matrix_block_g = _mm_loadu_pd(&(matrix_[3][0]));
1448
1449 // First column.
1450 __m128d other_matrix_first_param = _mm_set1_pd(mat.matrix_[0][0]);
1451 __m128d other_matrix_second_param = _mm_set1_pd(mat.matrix_[0][1]);
1452 __m128d other_matrix_third_param = _mm_set1_pd(mat.matrix_[0][2]);
1453 __m128d other_matrix_fourth_param = _mm_set1_pd(mat.matrix_[0][3]);
1454
1455 // output00 and output01.
1456 __m128d accumulator = _mm_mul_pd(matrix_block_a, other_matrix_first_param);
1457 __m128d temp1 = _mm_mul_pd(matrix_block_c, other_matrix_second_param);
1458 __m128d temp2 = _mm_mul_pd(matrix_block_e, other_matrix_third_param);
1459 __m128d temp3 = _mm_mul_pd(matrix_block_g, other_matrix_fourth_param);
1460
1461 __m128d matrix_block_b = _mm_loadu_pd(&(matrix_[0][2]));
1462 __m128d matrix_block_d = _mm_loadu_pd(&(matrix_[1][2]));
1463 __m128d matrix_block_f = _mm_loadu_pd(&(matrix_[2][2]));
1464 __m128d matrix_block_h = _mm_loadu_pd(&(matrix_[3][2]));
1465
1466 accumulator = _mm_add_pd(accumulator, temp1);
1467 accumulator = _mm_add_pd(accumulator, temp2);
1468 accumulator = _mm_add_pd(accumulator, temp3);
1469 _mm_storeu_pd(&matrix_[0][0], accumulator);
1470
1471 // output02 and output03.
1472 accumulator = _mm_mul_pd(matrix_block_b, other_matrix_first_param);
1473 temp1 = _mm_mul_pd(matrix_block_d, other_matrix_second_param);
1474 temp2 = _mm_mul_pd(matrix_block_f, other_matrix_third_param);
1475 temp3 = _mm_mul_pd(matrix_block_h, other_matrix_fourth_param);
1476
1477 accumulator = _mm_add_pd(accumulator, temp1);
1478 accumulator = _mm_add_pd(accumulator, temp2);
1479 accumulator = _mm_add_pd(accumulator, temp3);
1480 _mm_storeu_pd(&matrix_[0][2], accumulator);
1481
1482 // Second column.
1483 other_matrix_first_param = _mm_set1_pd(mat.matrix_[1][0]);
1484 other_matrix_second_param = _mm_set1_pd(mat.matrix_[1][1]);
1485 other_matrix_third_param = _mm_set1_pd(mat.matrix_[1][2]);
1486 other_matrix_fourth_param = _mm_set1_pd(mat.matrix_[1][3]);
1487
1488 // output10 and output11.
1489 accumulator = _mm_mul_pd(matrix_block_a, other_matrix_first_param);
1490 temp1 = _mm_mul_pd(matrix_block_c, other_matrix_second_param);
1491 temp2 = _mm_mul_pd(matrix_block_e, other_matrix_third_param);
1492 temp3 = _mm_mul_pd(matrix_block_g, other_matrix_fourth_param);
1493
1494 accumulator = _mm_add_pd(accumulator, temp1);
1495 accumulator = _mm_add_pd(accumulator, temp2);
1496 accumulator = _mm_add_pd(accumulator, temp3);
1497 _mm_storeu_pd(&matrix_[1][0], accumulator);
1498
1499 // output12 and output13.
1500 accumulator = _mm_mul_pd(matrix_block_b, other_matrix_first_param);
1501 temp1 = _mm_mul_pd(matrix_block_d, other_matrix_second_param);
1502 temp2 = _mm_mul_pd(matrix_block_f, other_matrix_third_param);
1503 temp3 = _mm_mul_pd(matrix_block_h, other_matrix_fourth_param);
1504
1505 accumulator = _mm_add_pd(accumulator, temp1);
1506 accumulator = _mm_add_pd(accumulator, temp2);
1507 accumulator = _mm_add_pd(accumulator, temp3);
1508 _mm_storeu_pd(&matrix_[1][2], accumulator);
1509
1510 // Third column.
1511 other_matrix_first_param = _mm_set1_pd(mat.matrix_[2][0]);
1512 other_matrix_second_param = _mm_set1_pd(mat.matrix_[2][1]);
1513 other_matrix_third_param = _mm_set1_pd(mat.matrix_[2][2]);
1514 other_matrix_fourth_param = _mm_set1_pd(mat.matrix_[2][3]);
1515
1516 // output20 and output21.
1517 accumulator = _mm_mul_pd(matrix_block_a, other_matrix_first_param);
1518 temp1 = _mm_mul_pd(matrix_block_c, other_matrix_second_param);
1519 temp2 = _mm_mul_pd(matrix_block_e, other_matrix_third_param);
1520 temp3 = _mm_mul_pd(matrix_block_g, other_matrix_fourth_param);
1521
1522 accumulator = _mm_add_pd(accumulator, temp1);
1523 accumulator = _mm_add_pd(accumulator, temp2);
1524 accumulator = _mm_add_pd(accumulator, temp3);
1525 _mm_storeu_pd(&matrix_[2][0], accumulator);
1526
1527 // output22 and output23.
1528 accumulator = _mm_mul_pd(matrix_block_b, other_matrix_first_param);
1529 temp1 = _mm_mul_pd(matrix_block_d, other_matrix_second_param);
1530 temp2 = _mm_mul_pd(matrix_block_f, other_matrix_third_param);
1531 temp3 = _mm_mul_pd(matrix_block_h, other_matrix_fourth_param);
1532
1533 accumulator = _mm_add_pd(accumulator, temp1);
1534 accumulator = _mm_add_pd(accumulator, temp2);
1535 accumulator = _mm_add_pd(accumulator, temp3);
1536 _mm_storeu_pd(&matrix_[2][2], accumulator);
1537
1538 // Fourth column.
1539 other_matrix_first_param = _mm_set1_pd(mat.matrix_[3][0]);
1540 other_matrix_second_param = _mm_set1_pd(mat.matrix_[3][1]);
1541 other_matrix_third_param = _mm_set1_pd(mat.matrix_[3][2]);
1542 other_matrix_fourth_param = _mm_set1_pd(mat.matrix_[3][3]);
1543
1544 // output30 and output31.
1545 accumulator = _mm_mul_pd(matrix_block_a, other_matrix_first_param);
1546 temp1 = _mm_mul_pd(matrix_block_c, other_matrix_second_param);
1547 temp2 = _mm_mul_pd(matrix_block_e, other_matrix_third_param);
1548 temp3 = _mm_mul_pd(matrix_block_g, other_matrix_fourth_param);
1549
1550 accumulator = _mm_add_pd(accumulator, temp1);
1551 accumulator = _mm_add_pd(accumulator, temp2);
1552 accumulator = _mm_add_pd(accumulator, temp3);
1553 _mm_storeu_pd(&matrix_[3][0], accumulator);
1554
1555 // output32 and output33.
1556 accumulator = _mm_mul_pd(matrix_block_b, other_matrix_first_param);
1557 temp1 = _mm_mul_pd(matrix_block_d, other_matrix_second_param);
1558 temp2 = _mm_mul_pd(matrix_block_f, other_matrix_third_param);
1559 temp3 = _mm_mul_pd(matrix_block_h, other_matrix_fourth_param);
1560
1561 accumulator = _mm_add_pd(accumulator, temp1);
1562 accumulator = _mm_add_pd(accumulator, temp2);
1563 accumulator = _mm_add_pd(accumulator, temp3);
1564 _mm_storeu_pd(&matrix_[3][2], accumulator);
1565 #else
1566 Matrix4 tmp;
1567
1568 tmp[0][0] =
1569 (mat.matrix_[0][0] * matrix_[0][0] + mat.matrix_[0][1] * matrix_[1][0] +
1570 mat.matrix_[0][2] * matrix_[2][0] + mat.matrix_[0][3] * matrix_[3][0]);
1571 tmp[0][1] =
1572 (mat.matrix_[0][0] * matrix_[0][1] + mat.matrix_[0][1] * matrix_[1][1] +
1573 mat.matrix_[0][2] * matrix_[2][1] + mat.matrix_[0][3] * matrix_[3][1]);
1574 tmp[0][2] =
1575 (mat.matrix_[0][0] * matrix_[0][2] + mat.matrix_[0][1] * matrix_[1][2] +
1576 mat.matrix_[0][2] * matrix_[2][2] + mat.matrix_[0][3] * matrix_[3][2]);
1577 tmp[0][3] =
1578 (mat.matrix_[0][0] * matrix_[0][3] + mat.matrix_[0][1] * matrix_[1][3] +
1579 mat.matrix_[0][2] * matrix_[2][3] + mat.matrix_[0][3] * matrix_[3][3]);
1580
1581 tmp[1][0] =
1582 (mat.matrix_[1][0] * matrix_[0][0] + mat.matrix_[1][1] * matrix_[1][0] +
1583 mat.matrix_[1][2] * matrix_[2][0] + mat.matrix_[1][3] * matrix_[3][0]);
1584 tmp[1][1] =
1585 (mat.matrix_[1][0] * matrix_[0][1] + mat.matrix_[1][1] * matrix_[1][1] +
1586 mat.matrix_[1][2] * matrix_[2][1] + mat.matrix_[1][3] * matrix_[3][1]);
1587 tmp[1][2] =
1588 (mat.matrix_[1][0] * matrix_[0][2] + mat.matrix_[1][1] * matrix_[1][2] +
1589 mat.matrix_[1][2] * matrix_[2][2] + mat.matrix_[1][3] * matrix_[3][2]);
1590 tmp[1][3] =
1591 (mat.matrix_[1][0] * matrix_[0][3] + mat.matrix_[1][1] * matrix_[1][3] +
1592 mat.matrix_[1][2] * matrix_[2][3] + mat.matrix_[1][3] * matrix_[3][3]);
1593
1594 tmp[2][0] =
1595 (mat.matrix_[2][0] * matrix_[0][0] + mat.matrix_[2][1] * matrix_[1][0] +
1596 mat.matrix_[2][2] * matrix_[2][0] + mat.matrix_[2][3] * matrix_[3][0]);
1597 tmp[2][1] =
1598 (mat.matrix_[2][0] * matrix_[0][1] + mat.matrix_[2][1] * matrix_[1][1] +
1599 mat.matrix_[2][2] * matrix_[2][1] + mat.matrix_[2][3] * matrix_[3][1]);
1600 tmp[2][2] =
1601 (mat.matrix_[2][0] * matrix_[0][2] + mat.matrix_[2][1] * matrix_[1][2] +
1602 mat.matrix_[2][2] * matrix_[2][2] + mat.matrix_[2][3] * matrix_[3][2]);
1603 tmp[2][3] =
1604 (mat.matrix_[2][0] * matrix_[0][3] + mat.matrix_[2][1] * matrix_[1][3] +
1605 mat.matrix_[2][2] * matrix_[2][3] + mat.matrix_[2][3] * matrix_[3][3]);
1606
1607 tmp[3][0] =
1608 (mat.matrix_[3][0] * matrix_[0][0] + mat.matrix_[3][1] * matrix_[1][0] +
1609 mat.matrix_[3][2] * matrix_[2][0] + mat.matrix_[3][3] * matrix_[3][0]);
1610 tmp[3][1] =
1611 (mat.matrix_[3][0] * matrix_[0][1] + mat.matrix_[3][1] * matrix_[1][1] +
1612 mat.matrix_[3][2] * matrix_[2][1] + mat.matrix_[3][3] * matrix_[3][1]);
1613 tmp[3][2] =
1614 (mat.matrix_[3][0] * matrix_[0][2] + mat.matrix_[3][1] * matrix_[1][2] +
1615 mat.matrix_[3][2] * matrix_[2][2] + mat.matrix_[3][3] * matrix_[3][2]);
1616 tmp[3][3] =
1617 (mat.matrix_[3][0] * matrix_[0][3] + mat.matrix_[3][1] * matrix_[1][3] +
1618 mat.matrix_[3][2] * matrix_[2][3] + mat.matrix_[3][3] * matrix_[3][3]);
1619
1620 SetMatrix(tmp);
1621 #endif
1622 return *this;
1623 }
1624
MultVecMatrix(double x,double y,double & result_x,double & result_y) const1625 void TransformationMatrix::MultVecMatrix(double x,
1626 double y,
1627 double& result_x,
1628 double& result_y) const {
1629 result_x = matrix_[3][0] + x * matrix_[0][0] + y * matrix_[1][0];
1630 result_y = matrix_[3][1] + x * matrix_[0][1] + y * matrix_[1][1];
1631 double w = matrix_[3][3] + x * matrix_[0][3] + y * matrix_[1][3];
1632 if (w != 1 && w != 0) {
1633 result_x /= w;
1634 result_y /= w;
1635 }
1636 }
1637
MultVecMatrix(double x,double y,double z,double & result_x,double & result_y,double & result_z) const1638 void TransformationMatrix::MultVecMatrix(double x,
1639 double y,
1640 double z,
1641 double& result_x,
1642 double& result_y,
1643 double& result_z) const {
1644 result_x =
1645 matrix_[3][0] + x * matrix_[0][0] + y * matrix_[1][0] + z * matrix_[2][0];
1646 result_y =
1647 matrix_[3][1] + x * matrix_[0][1] + y * matrix_[1][1] + z * matrix_[2][1];
1648 result_z =
1649 matrix_[3][2] + x * matrix_[0][2] + y * matrix_[1][2] + z * matrix_[2][2];
1650 double w =
1651 matrix_[3][3] + x * matrix_[0][3] + y * matrix_[1][3] + z * matrix_[2][3];
1652 if (w != 1 && w != 0) {
1653 result_x /= w;
1654 result_y /= w;
1655 result_z /= w;
1656 }
1657 }
1658
IsInvertible() const1659 bool TransformationMatrix::IsInvertible() const {
1660 return IsIdentityOrTranslation() || blink::Determinant4x4(matrix_) != 0;
1661 }
1662
Inverse() const1663 TransformationMatrix TransformationMatrix::Inverse() const {
1664 if (IsIdentityOrTranslation()) {
1665 // identity matrix
1666 if (matrix_[3][0] == 0 && matrix_[3][1] == 0 && matrix_[3][2] == 0)
1667 return TransformationMatrix();
1668
1669 // translation
1670 return TransformationMatrix(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0,
1671 -matrix_[3][0], -matrix_[3][1], -matrix_[3][2],
1672 1);
1673 }
1674
1675 TransformationMatrix inv_mat;
1676 bool inverted = blink::Inverse(matrix_, inv_mat.matrix_);
1677 if (!inverted)
1678 return TransformationMatrix();
1679
1680 return inv_mat;
1681 }
1682
MakeAffine()1683 void TransformationMatrix::MakeAffine() {
1684 matrix_[0][2] = 0;
1685 matrix_[0][3] = 0;
1686
1687 matrix_[1][2] = 0;
1688 matrix_[1][3] = 0;
1689
1690 matrix_[2][0] = 0;
1691 matrix_[2][1] = 0;
1692 matrix_[2][2] = 1;
1693 matrix_[2][3] = 0;
1694
1695 matrix_[3][2] = 0;
1696 matrix_[3][3] = 1;
1697 }
1698
ToAffineTransform() const1699 AffineTransform TransformationMatrix::ToAffineTransform() const {
1700 return AffineTransform(matrix_[0][0], matrix_[0][1], matrix_[1][0],
1701 matrix_[1][1], matrix_[3][0], matrix_[3][1]);
1702 }
1703
FlattenTo2d()1704 void TransformationMatrix::FlattenTo2d() {
1705 matrix_[2][0] = 0;
1706 matrix_[2][1] = 0;
1707 matrix_[0][2] = 0;
1708 matrix_[1][2] = 0;
1709 matrix_[2][2] = 1;
1710 matrix_[3][2] = 0;
1711 matrix_[2][3] = 0;
1712 }
1713
BlendFloat(double & from,double to,double progress)1714 static inline void BlendFloat(double& from, double to, double progress) {
1715 if (from != to)
1716 from = from + (to - from) * progress;
1717 }
1718
Is2dTransform() const1719 bool TransformationMatrix::Is2dTransform() const {
1720 if (!IsFlat())
1721 return false;
1722
1723 // Check perspective.
1724 if (matrix_[0][3] != 0 || matrix_[1][3] != 0 || matrix_[2][3] != 0 ||
1725 matrix_[3][3] != 1)
1726 return false;
1727
1728 return true;
1729 }
1730
Blend(const TransformationMatrix & from,double progress)1731 void TransformationMatrix::Blend(const TransformationMatrix& from,
1732 double progress) {
1733 if (from.IsIdentity() && IsIdentity())
1734 return;
1735
1736 if (from.Is2dTransform() && Is2dTransform()) {
1737 Blend2D(from, progress);
1738 return;
1739 }
1740
1741 // decompose
1742 DecomposedType from_decomp;
1743 DecomposedType to_decomp;
1744 if (!from.Decompose(from_decomp) || !Decompose(to_decomp)) {
1745 if (progress < 0.5)
1746 *this = from;
1747 return;
1748 }
1749
1750 // interpolate
1751 BlendFloat(from_decomp.scale_x, to_decomp.scale_x, progress);
1752 BlendFloat(from_decomp.scale_y, to_decomp.scale_y, progress);
1753 BlendFloat(from_decomp.scale_z, to_decomp.scale_z, progress);
1754 BlendFloat(from_decomp.skew_xy, to_decomp.skew_xy, progress);
1755 BlendFloat(from_decomp.skew_xz, to_decomp.skew_xz, progress);
1756 BlendFloat(from_decomp.skew_yz, to_decomp.skew_yz, progress);
1757 BlendFloat(from_decomp.translate_x, to_decomp.translate_x, progress);
1758 BlendFloat(from_decomp.translate_y, to_decomp.translate_y, progress);
1759 BlendFloat(from_decomp.translate_z, to_decomp.translate_z, progress);
1760 BlendFloat(from_decomp.perspective_x, to_decomp.perspective_x, progress);
1761 BlendFloat(from_decomp.perspective_y, to_decomp.perspective_y, progress);
1762 BlendFloat(from_decomp.perspective_z, to_decomp.perspective_z, progress);
1763 BlendFloat(from_decomp.perspective_w, to_decomp.perspective_w, progress);
1764
1765 Slerp(from_decomp, to_decomp, progress);
1766
1767 // recompose
1768 Recompose(from_decomp);
1769 }
1770
Blend2D(const TransformationMatrix & from,double progress)1771 void TransformationMatrix::Blend2D(const TransformationMatrix& from,
1772 double progress) {
1773 // Decompose into scale, rotate, translate and skew transforms.
1774 Decomposed2dType from_decomp;
1775 Decomposed2dType to_decomp;
1776 if (!from.Decompose2D(from_decomp) || !Decompose2D(to_decomp)) {
1777 if (progress < 0.5)
1778 *this = from;
1779 return;
1780 }
1781
1782 // Take the shorter of the clockwise or counter-clockwise paths.
1783 double rotation = abs(from_decomp.angle - to_decomp.angle);
1784 DCHECK(rotation < 2 * M_PI);
1785 if (rotation > M_PI) {
1786 if (from_decomp.angle > to_decomp.angle) {
1787 from_decomp.angle -= 2 * M_PI;
1788 } else {
1789 to_decomp.angle -= 2 * M_PI;
1790 }
1791 }
1792
1793 // Interpolate.
1794 BlendFloat(from_decomp.scale_x, to_decomp.scale_x, progress);
1795 BlendFloat(from_decomp.scale_y, to_decomp.scale_y, progress);
1796 BlendFloat(from_decomp.skew_xy, to_decomp.skew_xy, progress);
1797 BlendFloat(from_decomp.translate_x, to_decomp.translate_x, progress);
1798 BlendFloat(from_decomp.translate_y, to_decomp.translate_y, progress);
1799 BlendFloat(from_decomp.angle, to_decomp.angle, progress);
1800
1801 // Recompose.
1802 Recompose2D(from_decomp);
1803 }
1804
Decompose(DecomposedType & decomp) const1805 bool TransformationMatrix::Decompose(DecomposedType& decomp) const {
1806 if (IsIdentity()) {
1807 memset(&decomp, 0, sizeof(decomp));
1808 decomp.perspective_w = 1;
1809 decomp.scale_x = 1;
1810 decomp.scale_y = 1;
1811 decomp.scale_z = 1;
1812 }
1813
1814 if (!blink::Decompose(matrix_, decomp))
1815 return false;
1816 return true;
1817 }
1818
1819 // Decompose a 2D transformation matrix of the form:
1820 // [m11 m21 0 m41]
1821 // [m12 m22 0 m42]
1822 // [ 0 0 1 0 ]
1823 // [ 0 0 0 1 ]
1824 //
1825 // The decomposition is of the form:
1826 // M = translate * rotate * skew * scale
1827 // [1 0 0 Tx] [cos(R) -sin(R) 0 0] [1 K 0 0] [Sx 0 0 0]
1828 // = [0 1 0 Ty] [sin(R) cos(R) 0 0] [0 1 0 0] [0 Sy 0 0]
1829 // [0 0 1 0 ] [ 0 0 1 0] [0 0 1 0] [0 0 1 0]
1830 // [0 0 0 1 ] [ 0 0 0 1] [0 0 0 1] [0 0 0 1]
1831 //
Decompose2D(Decomposed2dType & decomp) const1832 bool TransformationMatrix::Decompose2D(Decomposed2dType& decomp) const {
1833 if (!Is2dTransform()) {
1834 LOG(ERROR) << "2-D decomposition cannot be performed on a 3-D transform.";
1835 return false;
1836 }
1837
1838 double m11 = matrix_[0][0];
1839 double m21 = matrix_[1][0];
1840 double m12 = matrix_[0][1];
1841 double m22 = matrix_[1][1];
1842
1843 double determinant = m11 * m22 - m12 * m21;
1844 // Test for matrix being singular.
1845 if (determinant == 0) {
1846 return false;
1847 }
1848
1849 // Translation transform.
1850 // [m11 m21 0 m41] [1 0 0 Tx] [m11 m21 0 0]
1851 // [m12 m22 0 m42] = [0 1 0 Ty] [m12 m22 0 0]
1852 // [ 0 0 1 0 ] [0 0 1 0 ] [ 0 0 1 0]
1853 // [ 0 0 0 1 ] [0 0 0 1 ] [ 0 0 0 1]
1854 decomp.translate_x = matrix_[3][0];
1855 decomp.translate_y = matrix_[3][1];
1856
1857 // For the remainder of the decomposition process, we can focus on the upper
1858 // 2x2 submatrix
1859 // [m11 m21] = [cos(R) -sin(R)] [1 K] [Sx 0 ]
1860 // [m12 m22] [sin(R) cos(R)] [0 1] [0 Sy]
1861 // = [Sx*cos(R) Sy*(K*cos(R) - sin(R))]
1862 // [Sx*sin(R) Sy*(K*sin(R) + cos(R))]
1863
1864 // Determine sign of the x and y scale.
1865 decomp.scale_x = 1;
1866 decomp.scale_y = 1;
1867 if (determinant < 0) {
1868 // If the determinant is negative, we need to flip either the x or y scale.
1869 // Flipping both is equivalent to rotating by 180 degrees.
1870 // Flip the axis with the minimum unit vector dot product.
1871 if (m11 < m22) {
1872 decomp.scale_x = -decomp.scale_x;
1873 } else {
1874 decomp.scale_y = -decomp.scale_y;
1875 }
1876 }
1877
1878 // X Scale.
1879 // m11^2 + m12^2 = Sx^2*(cos^2(R) + sin^2(R)) = Sx^2.
1880 // Sx = +/-sqrt(m11^2 + m22^2)
1881 decomp.scale_x *= sqrt(m11 * m11 + m12 * m12);
1882 m11 /= decomp.scale_x;
1883 m12 /= decomp.scale_x;
1884
1885 // Post normalization, the submatrix is now of the form:
1886 // [m11 m21] = [cos(R) Sy*(K*cos(R) - sin(R))]
1887 // [m12 m22] [sin(R) Sy*(K*sin(R) + cos(R))]
1888
1889 // XY Shear.
1890 // m11 * m21 + m12 * m22 = Sy*K*cos^2(R) - Sy*sin(R)*cos(R) +
1891 // Sy*K*sin^2(R) + Sy*cos(R)*sin(R)
1892 // = Sy*K
1893 double scaledShear = m11 * m21 + m12 * m22;
1894 m21 -= m11 * scaledShear;
1895 m22 -= m12 * scaledShear;
1896
1897 // Post normalization, the submatrix is now of the form:
1898 // [m11 m21] = [cos(R) -Sy*sin(R)]
1899 // [m12 m22] [sin(R) Sy*cos(R)]
1900
1901 // Y Scale.
1902 // Similar process to determining x-scale.
1903 decomp.scale_y *= sqrt(m21 * m21 + m22 * m22);
1904 m21 /= decomp.scale_y;
1905 m22 /= decomp.scale_y;
1906 decomp.skew_xy = scaledShear / decomp.scale_y;
1907
1908 // Rotation transform.
1909 decomp.angle = atan2(m12, m11);
1910 return true;
1911 }
1912
Recompose(const DecomposedType & decomp)1913 void TransformationMatrix::Recompose(const DecomposedType& decomp) {
1914 MakeIdentity();
1915
1916 // first apply perspective
1917 matrix_[0][3] = decomp.perspective_x;
1918 matrix_[1][3] = decomp.perspective_y;
1919 matrix_[2][3] = decomp.perspective_z;
1920 matrix_[3][3] = decomp.perspective_w;
1921
1922 // now translate
1923 Translate3d(decomp.translate_x, decomp.translate_y, decomp.translate_z);
1924
1925 // apply rotation
1926 double xx = decomp.quaternion_x * decomp.quaternion_x;
1927 double xy = decomp.quaternion_x * decomp.quaternion_y;
1928 double xz = decomp.quaternion_x * decomp.quaternion_z;
1929 double xw = decomp.quaternion_x * decomp.quaternion_w;
1930 double yy = decomp.quaternion_y * decomp.quaternion_y;
1931 double yz = decomp.quaternion_y * decomp.quaternion_z;
1932 double yw = decomp.quaternion_y * decomp.quaternion_w;
1933 double zz = decomp.quaternion_z * decomp.quaternion_z;
1934 double zw = decomp.quaternion_z * decomp.quaternion_w;
1935
1936 // Construct a composite rotation matrix from the quaternion values.
1937 // Arguments are in column order.
1938 // https://en.wikipedia.org/wiki/Rotation_matrix#Quaternion
1939 TransformationMatrix rotation_matrix(1 - 2 * (yy + zz), // Q_xx
1940 2 * (xy + zw), // Q_yx
1941 2 * (xz - yw), 0, // Q_zx
1942 2 * (xy - zw), // Q_xy
1943 1 - 2 * (xx + zz), // Q_yy
1944 2 * (yz + xw), 0, // Q_zy
1945 2 * (xz + yw), // Q_xz
1946 2 * (yz - xw), // Q_yz
1947 1 - 2 * (xx + yy), 0, // Q_zz
1948 0, 0, 0, 1);
1949
1950 Multiply(rotation_matrix);
1951
1952 // now apply skew
1953 if (decomp.skew_yz) {
1954 TransformationMatrix tmp;
1955 tmp.SetM32(decomp.skew_yz);
1956 Multiply(tmp);
1957 }
1958
1959 if (decomp.skew_xz) {
1960 TransformationMatrix tmp;
1961 tmp.SetM31(decomp.skew_xz);
1962 Multiply(tmp);
1963 }
1964
1965 if (decomp.skew_xy) {
1966 TransformationMatrix tmp;
1967 tmp.SetM21(decomp.skew_xy);
1968 Multiply(tmp);
1969 }
1970
1971 // finally, apply scale
1972 Scale3d(decomp.scale_x, decomp.scale_y, decomp.scale_z);
1973 }
1974
Recompose2D(const Decomposed2dType & decomp)1975 void TransformationMatrix::Recompose2D(const Decomposed2dType& decomp) {
1976 MakeIdentity();
1977
1978 // Translate transform.
1979 SetM41(decomp.translate_x);
1980 SetM42(decomp.translate_y);
1981
1982 // Rotate transform.
1983 double cosAngle = cos(decomp.angle);
1984 double sinAngle = sin(decomp.angle);
1985 SetM11(cosAngle);
1986 SetM21(-sinAngle);
1987 SetM12(sinAngle);
1988 SetM22(cosAngle);
1989
1990 // skew transform.
1991 if (decomp.skew_xy) {
1992 TransformationMatrix skewTransform;
1993 skewTransform.SetM21(decomp.skew_xy);
1994 Multiply(skewTransform);
1995 }
1996
1997 // Scale transform.
1998 Scale3d(decomp.scale_x, decomp.scale_y, 1);
1999 }
2000
IsIntegerTranslation() const2001 bool TransformationMatrix::IsIntegerTranslation() const {
2002 if (!IsIdentityOrTranslation())
2003 return false;
2004
2005 // Check for translate Z.
2006 if (matrix_[3][2])
2007 return false;
2008
2009 // Check for non-integer translate X/Y.
2010 if (static_cast<int>(matrix_[3][0]) != matrix_[3][0] ||
2011 static_cast<int>(matrix_[3][1]) != matrix_[3][1])
2012 return false;
2013
2014 return true;
2015 }
2016
2017 // This is the same as gfx::Transform::Preserves2dAxisAlignment().
Preserves2dAxisAlignment() const2018 bool TransformationMatrix::Preserves2dAxisAlignment() const {
2019 // Check whether an axis aligned 2-dimensional rect would remain axis-aligned
2020 // after being transformed by this matrix (and implicitly projected by
2021 // dropping any non-zero z-values).
2022 //
2023 // The 4th column can be ignored because translations don't affect axis
2024 // alignment. The 3rd column can be ignored because we are assuming 2d
2025 // inputs, where z-values will be zero. The 3rd row can also be ignored
2026 // because we are assuming 2d outputs, and any resulting z-value is dropped
2027 // anyway. For the inner 2x2 portion, the only effects that keep a rect axis
2028 // aligned are (1) swapping axes and (2) scaling axes. This can be checked by
2029 // verifying only 1 element of every column and row is non-zero. Degenerate
2030 // cases that project the x or y dimension to zero are considered to preserve
2031 // axis alignment.
2032 //
2033 // If the matrix does have perspective component that is affected by x or y
2034 // values: The current implementation conservatively assumes that axis
2035 // alignment is not preserved.
2036 bool has_x_or_y_perspective = M14() != 0 || M24() != 0;
2037 if (has_x_or_y_perspective)
2038 return false;
2039
2040 // Use float epsilon here, not double, to round very small rotations back
2041 // to zero.
2042 constexpr double kEpsilon = std::numeric_limits<float>::epsilon();
2043
2044 int num_non_zero_in_row_1 = 0;
2045 int num_non_zero_in_row_2 = 0;
2046 int num_non_zero_in_col_1 = 0;
2047 int num_non_zero_in_col_2 = 0;
2048 if (std::abs(M11()) > kEpsilon) {
2049 num_non_zero_in_col_1++;
2050 num_non_zero_in_row_1++;
2051 }
2052 if (std::abs(M12()) > kEpsilon) {
2053 num_non_zero_in_col_1++;
2054 num_non_zero_in_row_2++;
2055 }
2056 if (std::abs(M21()) > kEpsilon) {
2057 num_non_zero_in_col_2++;
2058 num_non_zero_in_row_1++;
2059 }
2060 if (std::abs(M22()) > kEpsilon) {
2061 num_non_zero_in_col_2++;
2062 num_non_zero_in_row_2++;
2063 }
2064
2065 return num_non_zero_in_row_1 <= 1 && num_non_zero_in_row_2 <= 1 &&
2066 num_non_zero_in_col_1 <= 1 && num_non_zero_in_col_2 <= 1;
2067 }
2068
ToColumnMajorFloatArray(FloatMatrix4 & result) const2069 void TransformationMatrix::ToColumnMajorFloatArray(FloatMatrix4& result) const {
2070 result[0] = M11();
2071 result[1] = M12();
2072 result[2] = M13();
2073 result[3] = M14();
2074 result[4] = M21();
2075 result[5] = M22();
2076 result[6] = M23();
2077 result[7] = M24();
2078 result[8] = M31();
2079 result[9] = M32();
2080 result[10] = M33();
2081 result[11] = M34();
2082 result[12] = M41();
2083 result[13] = M42();
2084 result[14] = M43();
2085 result[15] = M44();
2086 }
2087
ToSkMatrix44(const TransformationMatrix & matrix)2088 SkMatrix44 TransformationMatrix::ToSkMatrix44(
2089 const TransformationMatrix& matrix) {
2090 SkMatrix44 ret(SkMatrix44::kUninitialized_Constructor);
2091 ret.set4x4(matrix.M11(), matrix.M12(), matrix.M13(), matrix.M14(),
2092 matrix.M21(), matrix.M22(), matrix.M23(), matrix.M24(),
2093 matrix.M31(), matrix.M32(), matrix.M33(), matrix.M34(),
2094 matrix.M41(), matrix.M42(), matrix.M43(), matrix.M44());
2095 return ret;
2096 }
2097
ToTransform(const TransformationMatrix & matrix)2098 gfx::Transform TransformationMatrix::ToTransform(
2099 const TransformationMatrix& matrix) {
2100 return gfx::Transform(matrix.M11(), matrix.M21(), matrix.M31(), matrix.M41(),
2101 matrix.M12(), matrix.M22(), matrix.M32(), matrix.M42(),
2102 matrix.M13(), matrix.M23(), matrix.M33(), matrix.M43(),
2103 matrix.M14(), matrix.M24(), matrix.M34(), matrix.M44());
2104 }
2105
ToString(bool as_matrix) const2106 String TransformationMatrix::ToString(bool as_matrix) const {
2107 if (as_matrix) {
2108 // Return as a matrix in row-major order.
2109 return String::Format(
2110 "[%lg,%lg,%lg,%lg,\n%lg,%lg,%lg,%lg,\n%lg,%lg,%lg,%lg,\n%lg,%lg,%lg,%"
2111 "lg]",
2112 M11(), M21(), M31(), M41(), M12(), M22(), M32(), M42(), M13(), M23(),
2113 M33(), M43(), M14(), M24(), M34(), M44());
2114 }
2115
2116 TransformationMatrix::DecomposedType decomposition;
2117 if (!Decompose(decomposition))
2118 return ToString(true) + " (degenerate)";
2119
2120 if (IsIdentityOrTranslation()) {
2121 if (decomposition.translate_x == 0 && decomposition.translate_y == 0 &&
2122 decomposition.translate_z == 0)
2123 return "identity";
2124 return String::Format("translation(%lg,%lg,%lg)", decomposition.translate_x,
2125 decomposition.translate_y, decomposition.translate_z);
2126 }
2127
2128 return String::Format(
2129 "translation(%lg,%lg,%lg), scale(%lg,%lg,%lg), skew(%lg,%lg,%lg), "
2130 "quaternion(%lg,%lg,%lg,%lg), perspective(%lg,%lg,%lg,%lg)",
2131 decomposition.translate_x, decomposition.translate_y,
2132 decomposition.translate_z, decomposition.scale_x, decomposition.scale_y,
2133 decomposition.scale_z, decomposition.skew_xy, decomposition.skew_xz,
2134 decomposition.skew_yz, decomposition.quaternion_x,
2135 decomposition.quaternion_y, decomposition.quaternion_z,
2136 decomposition.quaternion_w, decomposition.perspective_x,
2137 decomposition.perspective_y, decomposition.perspective_z,
2138 decomposition.perspective_w);
2139 }
2140
operator <<(std::ostream & ostream,const TransformationMatrix & transform)2141 std::ostream& operator<<(std::ostream& ostream,
2142 const TransformationMatrix& transform) {
2143 return ostream << transform.ToString();
2144 }
2145
RoundCloseToZero(double number)2146 static double RoundCloseToZero(double number) {
2147 return std::abs(number) < 1e-7 ? 0 : number;
2148 }
2149
TransformAsJSONArray(const TransformationMatrix & t)2150 std::unique_ptr<JSONArray> TransformAsJSONArray(const TransformationMatrix& t) {
2151 auto array = std::make_unique<JSONArray>();
2152 {
2153 auto row = std::make_unique<JSONArray>();
2154 row->PushDouble(RoundCloseToZero(t.M11()));
2155 row->PushDouble(RoundCloseToZero(t.M12()));
2156 row->PushDouble(RoundCloseToZero(t.M13()));
2157 row->PushDouble(RoundCloseToZero(t.M14()));
2158 array->PushArray(std::move(row));
2159 }
2160 {
2161 auto row = std::make_unique<JSONArray>();
2162 row->PushDouble(RoundCloseToZero(t.M21()));
2163 row->PushDouble(RoundCloseToZero(t.M22()));
2164 row->PushDouble(RoundCloseToZero(t.M23()));
2165 row->PushDouble(RoundCloseToZero(t.M24()));
2166 array->PushArray(std::move(row));
2167 }
2168 {
2169 auto row = std::make_unique<JSONArray>();
2170 row->PushDouble(RoundCloseToZero(t.M31()));
2171 row->PushDouble(RoundCloseToZero(t.M32()));
2172 row->PushDouble(RoundCloseToZero(t.M33()));
2173 row->PushDouble(RoundCloseToZero(t.M34()));
2174 array->PushArray(std::move(row));
2175 }
2176 {
2177 auto row = std::make_unique<JSONArray>();
2178 row->PushDouble(RoundCloseToZero(t.M41()));
2179 row->PushDouble(RoundCloseToZero(t.M42()));
2180 row->PushDouble(RoundCloseToZero(t.M43()));
2181 row->PushDouble(RoundCloseToZero(t.M44()));
2182 array->PushArray(std::move(row));
2183 }
2184 return array;
2185 }
2186
2187 } // namespace blink
2188