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 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 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 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 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 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 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 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 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 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 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) 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 */ 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 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 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 521 TransformationMatrix::TransformationMatrix(const AffineTransform& t) 522 { 523 setMatrix(t.a(), t.b(), t.c(), t.d(), t.e(), t.f()); 524 } 525 526 TransformationMatrix& TransformationMatrix::scale(double s) 527 { 528 return scaleNonUniform(s, s); 529 } 530 531 TransformationMatrix& TransformationMatrix::rotateFromVector(double x, double y) 532 { 533 return rotate(rad2deg(atan2(y, x))); 534 } 535 536 TransformationMatrix& TransformationMatrix::flipX() 537 { 538 return scaleNonUniform(-1.0, 1.0); 539 } 540 541 TransformationMatrix& TransformationMatrix::flipY() 542 { 543 return scaleNonUniform(1.0, -1.0); 544 } 545 546 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 595 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 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 626 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 648 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 670 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 678 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 688 IntRect TransformationMatrix::mapRect(const IntRect &rect) const 689 { 690 return enclosingIntRect(mapRect(FloatRect(rect))); 691 } 692 693 LayoutRect TransformationMatrix::mapRect(const LayoutRect& r) const 694 { 695 return enclosingLayoutRect(mapRect(FloatRect(r))); 696 } 697 698 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 718 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 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 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 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 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 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 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 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 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 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 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 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. 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 1330 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 1341 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 1354 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 1367 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 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 1406 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 1412 static inline void blendFloat(double& from, double to, double progress) 1413 { 1414 if (from != to) 1415 from = from + (to - from) * progress; 1416 } 1417 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 1453 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 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 1523 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 1539 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 1547 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 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