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.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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.
29 #include "platform/transforms/TransformationMatrix.h"
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"
38 #include "wtf/Assertions.h"
39 #include "wtf/MathExtras.h"
42 #include <emmintrin.h>
50 // Supporting Math Functions
52 // This is a set of function from various places (attributed inline) to do things like
53 // inversion and decomposition of a 4x4 matrix. They are used throughout the code
57 // Adapted from Matrix Inversion by Richard Carling, Graphics Gems <http://tog.acm.org/GraphicsGems/index.html>.
59 // EULA: The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code
60 // as your own and resell it. Using the code is permitted in any program, product, or library, non-commercial
61 // or commercial. Giving credit is not required, though is a nice gesture. The code comes as-is, and if there
62 // are any flaws or problems with any Gems code, nobody involved with Gems - authors, editors, publishers, or
63 // webmasters - are to be held responsible. Basically, don't be a jerk, and remember that anything free comes
66 // A clarification about the storage of matrix elements
68 // This class uses a 2 dimensional array internally to store the elements of the matrix. The first index into
69 // the array refers to the column that the element lies in; the second index refers to the row.
71 // In other words, this is the layout of the matrix:
73 // | m_matrix[0][0] m_matrix[1][0] m_matrix[2][0] m_matrix[3][0] |
74 // | m_matrix[0][1] m_matrix[1][1] m_matrix[2][1] m_matrix[3][1] |
75 // | m_matrix[0][2] m_matrix[1][2] m_matrix[2][2] m_matrix[3][2] |
76 // | m_matrix[0][3] m_matrix[1][3] m_matrix[2][3] m_matrix[3][3] |
78 typedef double Vector4[4];
79 typedef double Vector3[3];
81 const double SMALL_NUMBER = 1.e-8;
83 // inverse(original_matrix, inverse_matrix)
85 // calculate the inverse of a 4x4 matrix
88 // A = ___1__ adjoint A
91 // double = determinant2x2(double a, double b, double c, double d)
93 // calculate the determinant of a 2x2 matrix.
95 static double determinant2x2(double a, double b, double c, double d)
100 // double = determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3)
102 // Calculate the determinant of a 3x3 matrix
109 static double determinant3x3(double a1, double a2, double a3, double b1, double b2, double b3, double c1, double c2, double c3)
111 return a1 * determinant2x2(b2, b3, c2, c3)
112 - b1 * determinant2x2(a2, a3, c2, c3)
113 + c1 * determinant2x2(a2, a3, b2, b3);
116 // double = determinant4x4(matrix)
118 // calculate the determinant of a 4x4 matrix.
120 static double determinant4x4(const TransformationMatrix::Matrix4& m)
122 // Assign to individual variable names to aid selecting
145 return a1 * determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4)
146 - b1 * determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4)
147 + c1 * determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4)
148 - d1 * determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);
151 // adjoint( original_matrix, inverse_matrix )
153 // calculate the adjoint of a 4x4 matrix
155 // Let a denote the minor determinant of matrix A obtained by
158 // deleting the ith row and jth column from A.
164 // The matrix B = (b ) is the adjoint of A
167 static void adjoint(const TransformationMatrix::Matrix4& matrix, TransformationMatrix::Matrix4& result)
169 // Assign to individual variable names to aid
170 // selecting correct values
171 double a1 = matrix[0][0];
172 double b1 = matrix[0][1];
173 double c1 = matrix[0][2];
174 double d1 = matrix[0][3];
176 double a2 = matrix[1][0];
177 double b2 = matrix[1][1];
178 double c2 = matrix[1][2];
179 double d2 = matrix[1][3];
181 double a3 = matrix[2][0];
182 double b3 = matrix[2][1];
183 double c3 = matrix[2][2];
184 double d3 = matrix[2][3];
186 double a4 = matrix[3][0];
187 double b4 = matrix[3][1];
188 double c4 = matrix[3][2];
189 double d4 = matrix[3][3];
191 // Row column labeling reversed since we transpose rows & columns
192 result[0][0] = determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4);
193 result[1][0] = - determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4);
194 result[2][0] = determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4);
195 result[3][0] = - determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);
197 result[0][1] = - determinant3x3(b1, b3, b4, c1, c3, c4, d1, d3, d4);
198 result[1][1] = determinant3x3(a1, a3, a4, c1, c3, c4, d1, d3, d4);
199 result[2][1] = - determinant3x3(a1, a3, a4, b1, b3, b4, d1, d3, d4);
200 result[3][1] = determinant3x3(a1, a3, a4, b1, b3, b4, c1, c3, c4);
202 result[0][2] = determinant3x3(b1, b2, b4, c1, c2, c4, d1, d2, d4);
203 result[1][2] = - determinant3x3(a1, a2, a4, c1, c2, c4, d1, d2, d4);
204 result[2][2] = determinant3x3(a1, a2, a4, b1, b2, b4, d1, d2, d4);
205 result[3][2] = - determinant3x3(a1, a2, a4, b1, b2, b4, c1, c2, c4);
207 result[0][3] = - determinant3x3(b1, b2, b3, c1, c2, c3, d1, d2, d3);
208 result[1][3] = determinant3x3(a1, a2, a3, c1, c2, c3, d1, d2, d3);
209 result[2][3] = - determinant3x3(a1, a2, a3, b1, b2, b3, d1, d2, d3);
210 result[3][3] = determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3);
213 // Returns false if the matrix is not invertible
214 static bool inverse(const TransformationMatrix::Matrix4& matrix, TransformationMatrix::Matrix4& result)
216 // Calculate the adjoint matrix
217 adjoint(matrix, result);
219 // Calculate the 4x4 determinant
220 // If the determinant is zero,
221 // then the inverse matrix is not unique.
222 double det = determinant4x4(matrix);
224 if (fabs(det) < SMALL_NUMBER)
227 // Scale the adjoint matrix to get the inverse
229 for (int i = 0; i < 4; i++)
230 for (int j = 0; j < 4; j++)
231 result[i][j] = result[i][j] / det;
236 // End of code adapted from Matrix Inversion by Richard Carling
238 // Perform a decomposition on the passed matrix, return false if unsuccessful
239 // From Graphics Gems: unmatrix.c
241 // Transpose rotation portion of matrix a, return b
242 static void transposeMatrix4(const TransformationMatrix::Matrix4& a, TransformationMatrix::Matrix4& b)
244 for (int i = 0; i < 4; i++)
245 for (int j = 0; j < 4; j++)
249 // Multiply a homogeneous point by a matrix and return the transformed point
250 static void v4MulPointByMatrix(const Vector4 p, const TransformationMatrix::Matrix4& m, Vector4 result)
252 result[0] = (p[0] * m[0][0]) + (p[1] * m[1][0]) +
253 (p[2] * m[2][0]) + (p[3] * m[3][0]);
254 result[1] = (p[0] * m[0][1]) + (p[1] * m[1][1]) +
255 (p[2] * m[2][1]) + (p[3] * m[3][1]);
256 result[2] = (p[0] * m[0][2]) + (p[1] * m[1][2]) +
257 (p[2] * m[2][2]) + (p[3] * m[3][2]);
258 result[3] = (p[0] * m[0][3]) + (p[1] * m[1][3]) +
259 (p[2] * m[2][3]) + (p[3] * m[3][3]);
262 static double v3Length(Vector3 a)
264 return sqrt((a[0] * a[0]) + (a[1] * a[1]) + (a[2] * a[2]));
267 static void v3Scale(Vector3 v, double desiredLength)
269 double len = v3Length(v);
271 double l = desiredLength / len;
278 static double v3Dot(const Vector3 a, const Vector3 b)
280 return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]);
283 // Make a linear combination of two vectors and return the result.
284 // result = (a * ascl) + (b * bscl)
285 static void v3Combine(const Vector3 a, const Vector3 b, Vector3 result, double ascl, double bscl)
287 result[0] = (ascl * a[0]) + (bscl * b[0]);
288 result[1] = (ascl * a[1]) + (bscl * b[1]);
289 result[2] = (ascl * a[2]) + (bscl * b[2]);
292 // Return the cross product result = a cross b */
293 static void v3Cross(const Vector3 a, const Vector3 b, Vector3 result)
295 result[0] = (a[1] * b[2]) - (a[2] * b[1]);
296 result[1] = (a[2] * b[0]) - (a[0] * b[2]);
297 result[2] = (a[0] * b[1]) - (a[1] * b[0]);
300 static bool decompose(const TransformationMatrix::Matrix4& mat, TransformationMatrix::DecomposedType& result)
302 TransformationMatrix::Matrix4 localMatrix;
303 memcpy(localMatrix, mat, sizeof(TransformationMatrix::Matrix4));
305 // Normalize the matrix.
306 if (localMatrix[3][3] == 0)
310 for (i = 0; i < 4; i++)
311 for (j = 0; j < 4; j++)
312 localMatrix[i][j] /= localMatrix[3][3];
314 // perspectiveMatrix is used to solve for perspective, but it also provides
315 // an easy way to test for singularity of the upper 3x3 component.
316 TransformationMatrix::Matrix4 perspectiveMatrix;
317 memcpy(perspectiveMatrix, localMatrix, sizeof(TransformationMatrix::Matrix4));
318 for (i = 0; i < 3; i++)
319 perspectiveMatrix[i][3] = 0;
320 perspectiveMatrix[3][3] = 1;
322 if (determinant4x4(perspectiveMatrix) == 0)
325 // First, isolate perspective. This is the messiest.
326 if (localMatrix[0][3] != 0 || localMatrix[1][3] != 0 || localMatrix[2][3] != 0) {
327 // rightHandSide is the right hand side of the equation.
328 Vector4 rightHandSide;
329 rightHandSide[0] = localMatrix[0][3];
330 rightHandSide[1] = localMatrix[1][3];
331 rightHandSide[2] = localMatrix[2][3];
332 rightHandSide[3] = localMatrix[3][3];
334 // Solve the equation by inverting perspectiveMatrix and multiplying
335 // rightHandSide by the inverse. (This is the easiest way, not
336 // necessarily the best.)
337 TransformationMatrix::Matrix4 inversePerspectiveMatrix, transposedInversePerspectiveMatrix;
338 inverse(perspectiveMatrix, inversePerspectiveMatrix);
339 transposeMatrix4(inversePerspectiveMatrix, transposedInversePerspectiveMatrix);
341 Vector4 perspectivePoint;
342 v4MulPointByMatrix(rightHandSide, transposedInversePerspectiveMatrix, perspectivePoint);
344 result.perspectiveX = perspectivePoint[0];
345 result.perspectiveY = perspectivePoint[1];
346 result.perspectiveZ = perspectivePoint[2];
347 result.perspectiveW = perspectivePoint[3];
349 // Clear the perspective partition
350 localMatrix[0][3] = localMatrix[1][3] = localMatrix[2][3] = 0;
351 localMatrix[3][3] = 1;
354 result.perspectiveX = result.perspectiveY = result.perspectiveZ = 0;
355 result.perspectiveW = 1;
358 // Next take care of translation (easy).
359 result.translateX = localMatrix[3][0];
360 localMatrix[3][0] = 0;
361 result.translateY = localMatrix[3][1];
362 localMatrix[3][1] = 0;
363 result.translateZ = localMatrix[3][2];
364 localMatrix[3][2] = 0;
366 // Vector4 type and functions need to be added to the common set.
367 Vector3 row[3], pdum3;
369 // Now get scale and shear.
370 for (i = 0; i < 3; i++) {
371 row[i][0] = localMatrix[i][0];
372 row[i][1] = localMatrix[i][1];
373 row[i][2] = localMatrix[i][2];
376 // Compute X scale factor and normalize first row.
377 result.scaleX = v3Length(row[0]);
378 v3Scale(row[0], 1.0);
380 // Compute XY shear factor and make 2nd row orthogonal to 1st.
381 result.skewXY = v3Dot(row[0], row[1]);
382 v3Combine(row[1], row[0], row[1], 1.0, -result.skewXY);
384 // Now, compute Y scale and normalize 2nd row.
385 result.scaleY = v3Length(row[1]);
386 v3Scale(row[1], 1.0);
387 result.skewXY /= result.scaleY;
389 // Compute XZ and YZ shears, orthogonalize 3rd row.
390 result.skewXZ = v3Dot(row[0], row[2]);
391 v3Combine(row[2], row[0], row[2], 1.0, -result.skewXZ);
392 result.skewYZ = v3Dot(row[1], row[2]);
393 v3Combine(row[2], row[1], row[2], 1.0, -result.skewYZ);
395 // Next, get Z scale and normalize 3rd row.
396 result.scaleZ = v3Length(row[2]);
397 v3Scale(row[2], 1.0);
398 result.skewXZ /= result.scaleZ;
399 result.skewYZ /= result.scaleZ;
401 // At this point, the matrix (in rows[]) is orthonormal.
402 // Check for a coordinate system flip. If the determinant
403 // is -1, then negate the matrix and the scaling factors.
404 v3Cross(row[1], row[2], pdum3);
405 if (v3Dot(row[0], pdum3) < 0) {
411 for (i = 0; i < 3; i++) {
418 // Now, get the rotations out, as described in the gem.
420 // FIXME - Add the ability to return either quaternions (which are
421 // easier to recompose with) or Euler angles (rx, ry, rz), which
422 // are easier for authors to deal with. The latter will only be useful
423 // when we fix https://bugs.webkit.org/show_bug.cgi?id=23799, so I
424 // will leave the Euler angle code here for now.
426 // ret.rotateY = asin(-row[0][2]);
427 // if (cos(ret.rotateY) != 0) {
428 // ret.rotateX = atan2(row[1][2], row[2][2]);
429 // ret.rotateZ = atan2(row[0][1], row[0][0]);
431 // ret.rotateX = atan2(-row[2][0], row[1][1]);
435 double s, t, x, y, z, w;
437 t = row[0][0] + row[1][1] + row[2][2] + 1.0;
442 x = (row[2][1] - row[1][2]) * s;
443 y = (row[0][2] - row[2][0]) * s;
444 z = (row[1][0] - row[0][1]) * s;
445 } else if (row[0][0] > row[1][1] && row[0][0] > row[2][2]) {
446 s = sqrt (1.0 + row[0][0] - row[1][1] - row[2][2]) * 2.0; // S=4*qx
448 y = (row[0][1] + row[1][0]) / s;
449 z = (row[0][2] + row[2][0]) / s;
450 w = (row[2][1] - row[1][2]) / s;
451 } else if (row[1][1] > row[2][2]) {
452 s = sqrt (1.0 + row[1][1] - row[0][0] - row[2][2]) * 2.0; // S=4*qy
453 x = (row[0][1] + row[1][0]) / s;
455 z = (row[1][2] + row[2][1]) / s;
456 w = (row[0][2] - row[2][0]) / s;
458 s = sqrt(1.0 + row[2][2] - row[0][0] - row[1][1]) * 2.0; // S=4*qz
459 x = (row[0][2] + row[2][0]) / s;
460 y = (row[1][2] + row[2][1]) / s;
462 w = (row[1][0] - row[0][1]) / s;
465 result.quaternionX = x;
466 result.quaternionY = y;
467 result.quaternionZ = z;
468 result.quaternionW = w;
473 // Perform a spherical linear interpolation between the two
474 // passed quaternions with 0 <= t <= 1
475 static void slerp(double qa[4], const double qb[4], double t)
477 double ax, ay, az, aw;
478 double bx, by, bz, bw;
479 double cx, cy, cz, cw;
481 double th, invth, scale, invscale;
483 ax = qa[0]; ay = qa[1]; az = qa[2]; aw = qa[3];
484 bx = qb[0]; by = qb[1]; bz = qb[2]; bw = qb[3];
486 angle = ax * bx + ay * by + az * bz + aw * bw;
494 if (angle + 1.0 > .05) {
495 if (1.0 - angle >= .05) {
497 invth = 1.0 / sin (th);
498 scale = sin (th * (1.0 - t)) * invth;
499 invscale = sin (th * t) * invth;
509 scale = sin(piDouble * (.5 - t));
510 invscale = sin (piDouble * t);
513 cx = ax * scale + bx * invscale;
514 cy = ay * scale + by * invscale;
515 cz = az * scale + bz * invscale;
516 cw = aw * scale + bw * invscale;
518 qa[0] = cx; qa[1] = cy; qa[2] = cz; qa[3] = cw;
521 // End of Supporting Math Functions
523 TransformationMatrix::TransformationMatrix(const AffineTransform& t)
525 setMatrix(t.a(), t.b(), t.c(), t.d(), t.e(), t.f());
528 TransformationMatrix& TransformationMatrix::scale(double s)
530 return scaleNonUniform(s, s);
533 TransformationMatrix& TransformationMatrix::rotateFromVector(double x, double y)
535 return rotate(rad2deg(atan2(y, x)));
538 TransformationMatrix& TransformationMatrix::flipX()
540 return scaleNonUniform(-1.0, 1.0);
543 TransformationMatrix& TransformationMatrix::flipY()
545 return scaleNonUniform(1.0, -1.0);
548 FloatPoint TransformationMatrix::projectPoint(const FloatPoint& p, bool* clamped) const
550 // This is basically raytracing. We have a point in the destination
551 // plane with z=0, and we cast a ray parallel to the z-axis from that
552 // point to find the z-position at which it intersects the z=0 plane
553 // with the transform applied. Once we have that point we apply the
554 // inverse transform to find the corresponding point in the source
557 // Given a plane with normal Pn, and a ray starting at point R0 and
558 // with direction defined by the vector Rd, we can find the
559 // intersection point as a distance d from R0 in units of Rd by:
561 // d = -dot (Pn', R0) / dot (Pn', Rd)
566 // In this case, the projection plane is parallel to the ray we are trying to
567 // trace, and there is no well-defined value for the projection.
573 double z = -(m13() * x + m23() * y + m43()) / m33();
575 // FIXME: use multVecMatrix()
576 double outX = x * m11() + y * m21() + z * m31() + m41();
577 double outY = x * m12() + y * m22() + z * m32() + m42();
579 double w = x * m14() + y * m24() + z * m34() + m44();
581 // Using int max causes overflow when other code uses the projected point. To
582 // represent infinity yet reduce the risk of overflow, we use a large but
583 // not-too-large number here when clamping.
584 const int largeNumber = 100000000 / kFixedPointDenominator;
585 outX = copysign(largeNumber, outX);
586 outY = copysign(largeNumber, outY);
594 return FloatPoint(static_cast<float>(outX), static_cast<float>(outY));
597 FloatQuad TransformationMatrix::projectQuad(const FloatQuad& q, bool* clamped) const
599 FloatQuad projectedQuad;
601 bool clamped1 = false;
602 bool clamped2 = false;
603 bool clamped3 = false;
604 bool clamped4 = false;
606 projectedQuad.setP1(projectPoint(q.p1(), &clamped1));
607 projectedQuad.setP2(projectPoint(q.p2(), &clamped2));
608 projectedQuad.setP3(projectPoint(q.p3(), &clamped3));
609 projectedQuad.setP4(projectPoint(q.p4(), &clamped4));
612 *clamped = clamped1 || clamped2 || clamped3 || clamped4;
614 // If all points on the quad had w < 0, then the entire quad would not be visible to the projected surface.
615 bool everythingWasClipped = clamped1 && clamped2 && clamped3 && clamped4;
616 if (everythingWasClipped)
619 return projectedQuad;
622 static float clampEdgeValue(float f)
624 ASSERT(!std::isnan(f));
625 return min<float>(max<float>(f, (-LayoutUnit::max() / 2).toFloat()), (LayoutUnit::max() / 2).toFloat());
628 LayoutRect TransformationMatrix::clampedBoundsOfProjectedQuad(const FloatQuad& q) const
630 FloatRect mappedQuadBounds = projectQuad(q).boundingBox();
632 float left = clampEdgeValue(floorf(mappedQuadBounds.x()));
633 float top = clampEdgeValue(floorf(mappedQuadBounds.y()));
636 if (std::isinf(mappedQuadBounds.x()) && std::isinf(mappedQuadBounds.width()))
637 right = (LayoutUnit::max() / 2).toFloat();
639 right = clampEdgeValue(ceilf(mappedQuadBounds.maxX()));
642 if (std::isinf(mappedQuadBounds.y()) && std::isinf(mappedQuadBounds.height()))
643 bottom = (LayoutUnit::max() / 2).toFloat();
645 bottom = clampEdgeValue(ceilf(mappedQuadBounds.maxY()));
647 return LayoutRect(LayoutUnit::clamp(left), LayoutUnit::clamp(top), LayoutUnit::clamp(right - left), LayoutUnit::clamp(bottom - top));
650 void TransformationMatrix::transformBox(FloatBox& box) const
653 bool firstPoint = true;
654 for (size_t i = 0; i < 2; ++i) {
655 for (size_t j = 0; j < 2; ++j) {
656 for (size_t k = 0; k < 2; ++k) {
657 FloatPoint3D point(box.x(), box.y(), box.z());
658 point += FloatPoint3D(i * box.width(), j * box.height(), k * box.depth());
659 point = mapPoint(point);
661 bounds.setOrigin(point);
664 bounds.expandTo(point);
672 FloatPoint TransformationMatrix::mapPoint(const FloatPoint& p) const
674 if (isIdentityOrTranslation())
675 return FloatPoint(p.x() + static_cast<float>(m_matrix[3][0]), p.y() + static_cast<float>(m_matrix[3][1]));
677 return internalMapPoint(p);
680 FloatPoint3D TransformationMatrix::mapPoint(const FloatPoint3D& p) const
682 if (isIdentityOrTranslation())
683 return FloatPoint3D(p.x() + static_cast<float>(m_matrix[3][0]),
684 p.y() + static_cast<float>(m_matrix[3][1]),
685 p.z() + static_cast<float>(m_matrix[3][2]));
687 return internalMapPoint(p);
690 IntRect TransformationMatrix::mapRect(const IntRect &rect) const
692 return enclosingIntRect(mapRect(FloatRect(rect)));
695 LayoutRect TransformationMatrix::mapRect(const LayoutRect& r) const
697 return enclosingLayoutRect(mapRect(FloatRect(r)));
700 FloatRect TransformationMatrix::mapRect(const FloatRect& r) const
702 if (isIdentityOrTranslation()) {
703 FloatRect mappedRect(r);
704 mappedRect.move(static_cast<float>(m_matrix[3][0]), static_cast<float>(m_matrix[3][1]));
710 float maxX = r.maxX();
711 float maxY = r.maxY();
712 result.setP1(internalMapPoint(FloatPoint(r.x(), r.y())));
713 result.setP2(internalMapPoint(FloatPoint(maxX, r.y())));
714 result.setP3(internalMapPoint(FloatPoint(maxX, maxY)));
715 result.setP4(internalMapPoint(FloatPoint(r.x(), maxY)));
717 return result.boundingBox();
720 FloatQuad TransformationMatrix::mapQuad(const FloatQuad& q) const
722 if (isIdentityOrTranslation()) {
723 FloatQuad mappedQuad(q);
724 mappedQuad.move(static_cast<float>(m_matrix[3][0]), static_cast<float>(m_matrix[3][1]));
729 result.setP1(internalMapPoint(q.p1()));
730 result.setP2(internalMapPoint(q.p2()));
731 result.setP3(internalMapPoint(q.p3()));
732 result.setP4(internalMapPoint(q.p4()));
736 TransformationMatrix& TransformationMatrix::scaleNonUniform(double sx, double sy)
738 m_matrix[0][0] *= sx;
739 m_matrix[0][1] *= sx;
740 m_matrix[0][2] *= sx;
741 m_matrix[0][3] *= sx;
743 m_matrix[1][0] *= sy;
744 m_matrix[1][1] *= sy;
745 m_matrix[1][2] *= sy;
746 m_matrix[1][3] *= sy;
750 TransformationMatrix& TransformationMatrix::scale3d(double sx, double sy, double sz)
752 scaleNonUniform(sx, sy);
754 m_matrix[2][0] *= sz;
755 m_matrix[2][1] *= sz;
756 m_matrix[2][2] *= sz;
757 m_matrix[2][3] *= sz;
761 TransformationMatrix& TransformationMatrix::rotate3d(double x, double y, double z, double angle)
763 // Normalize the axis of rotation
764 double length = sqrt(x * x + y * y + z * z);
766 // A direction vector that cannot be normalized, such as [0, 0, 0], will cause the rotation to not be applied.
768 } else if (length != 1) {
774 // Angles are in degrees. Switch to radians.
775 angle = deg2rad(angle);
777 double sinTheta = sin(angle);
778 double cosTheta = cos(angle);
780 TransformationMatrix mat;
782 // Optimize cases where the axis is along a major axis
783 if (x == 1.0 && y == 0.0 && z == 0.0) {
784 mat.m_matrix[0][0] = 1.0;
785 mat.m_matrix[0][1] = 0.0;
786 mat.m_matrix[0][2] = 0.0;
787 mat.m_matrix[1][0] = 0.0;
788 mat.m_matrix[1][1] = cosTheta;
789 mat.m_matrix[1][2] = sinTheta;
790 mat.m_matrix[2][0] = 0.0;
791 mat.m_matrix[2][1] = -sinTheta;
792 mat.m_matrix[2][2] = cosTheta;
793 mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0;
794 mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0;
795 mat.m_matrix[3][3] = 1.0;
796 } else if (x == 0.0 && y == 1.0 && z == 0.0) {
797 mat.m_matrix[0][0] = cosTheta;
798 mat.m_matrix[0][1] = 0.0;
799 mat.m_matrix[0][2] = -sinTheta;
800 mat.m_matrix[1][0] = 0.0;
801 mat.m_matrix[1][1] = 1.0;
802 mat.m_matrix[1][2] = 0.0;
803 mat.m_matrix[2][0] = sinTheta;
804 mat.m_matrix[2][1] = 0.0;
805 mat.m_matrix[2][2] = cosTheta;
806 mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0;
807 mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0;
808 mat.m_matrix[3][3] = 1.0;
809 } else if (x == 0.0 && y == 0.0 && z == 1.0) {
810 mat.m_matrix[0][0] = cosTheta;
811 mat.m_matrix[0][1] = sinTheta;
812 mat.m_matrix[0][2] = 0.0;
813 mat.m_matrix[1][0] = -sinTheta;
814 mat.m_matrix[1][1] = cosTheta;
815 mat.m_matrix[1][2] = 0.0;
816 mat.m_matrix[2][0] = 0.0;
817 mat.m_matrix[2][1] = 0.0;
818 mat.m_matrix[2][2] = 1.0;
819 mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0;
820 mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0;
821 mat.m_matrix[3][3] = 1.0;
823 // This case is the rotation about an arbitrary unit vector.
825 // Formula is adapted from Wikipedia article on Rotation matrix,
826 // http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle
828 // An alternate resource with the same matrix: http://www.fastgraph.com/makegames/3drotation/
830 double oneMinusCosTheta = 1 - cosTheta;
831 mat.m_matrix[0][0] = cosTheta + x * x * oneMinusCosTheta;
832 mat.m_matrix[0][1] = y * x * oneMinusCosTheta + z * sinTheta;
833 mat.m_matrix[0][2] = z * x * oneMinusCosTheta - y * sinTheta;
834 mat.m_matrix[1][0] = x * y * oneMinusCosTheta - z * sinTheta;
835 mat.m_matrix[1][1] = cosTheta + y * y * oneMinusCosTheta;
836 mat.m_matrix[1][2] = z * y * oneMinusCosTheta + x * sinTheta;
837 mat.m_matrix[2][0] = x * z * oneMinusCosTheta + y * sinTheta;
838 mat.m_matrix[2][1] = y * z * oneMinusCosTheta - x * sinTheta;
839 mat.m_matrix[2][2] = cosTheta + z * z * oneMinusCosTheta;
840 mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0;
841 mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0;
842 mat.m_matrix[3][3] = 1.0;
848 TransformationMatrix& TransformationMatrix::rotate3d(double rx, double ry, double rz)
850 // Angles are in degrees. Switch to radians.
855 TransformationMatrix mat;
857 double sinTheta = sin(rz);
858 double cosTheta = cos(rz);
860 mat.m_matrix[0][0] = cosTheta;
861 mat.m_matrix[0][1] = sinTheta;
862 mat.m_matrix[0][2] = 0.0;
863 mat.m_matrix[1][0] = -sinTheta;
864 mat.m_matrix[1][1] = cosTheta;
865 mat.m_matrix[1][2] = 0.0;
866 mat.m_matrix[2][0] = 0.0;
867 mat.m_matrix[2][1] = 0.0;
868 mat.m_matrix[2][2] = 1.0;
869 mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0;
870 mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0;
871 mat.m_matrix[3][3] = 1.0;
873 TransformationMatrix rmat(mat);
878 mat.m_matrix[0][0] = cosTheta;
879 mat.m_matrix[0][1] = 0.0;
880 mat.m_matrix[0][2] = -sinTheta;
881 mat.m_matrix[1][0] = 0.0;
882 mat.m_matrix[1][1] = 1.0;
883 mat.m_matrix[1][2] = 0.0;
884 mat.m_matrix[2][0] = sinTheta;
885 mat.m_matrix[2][1] = 0.0;
886 mat.m_matrix[2][2] = cosTheta;
887 mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0;
888 mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0;
889 mat.m_matrix[3][3] = 1.0;
896 mat.m_matrix[0][0] = 1.0;
897 mat.m_matrix[0][1] = 0.0;
898 mat.m_matrix[0][2] = 0.0;
899 mat.m_matrix[1][0] = 0.0;
900 mat.m_matrix[1][1] = cosTheta;
901 mat.m_matrix[1][2] = sinTheta;
902 mat.m_matrix[2][0] = 0.0;
903 mat.m_matrix[2][1] = -sinTheta;
904 mat.m_matrix[2][2] = cosTheta;
905 mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0;
906 mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0;
907 mat.m_matrix[3][3] = 1.0;
915 TransformationMatrix& TransformationMatrix::translate(double tx, double ty)
917 m_matrix[3][0] += tx * m_matrix[0][0] + ty * m_matrix[1][0];
918 m_matrix[3][1] += tx * m_matrix[0][1] + ty * m_matrix[1][1];
919 m_matrix[3][2] += tx * m_matrix[0][2] + ty * m_matrix[1][2];
920 m_matrix[3][3] += tx * m_matrix[0][3] + ty * m_matrix[1][3];
924 TransformationMatrix& TransformationMatrix::translate3d(double tx, double ty, double tz)
926 m_matrix[3][0] += tx * m_matrix[0][0] + ty * m_matrix[1][0] + tz * m_matrix[2][0];
927 m_matrix[3][1] += tx * m_matrix[0][1] + ty * m_matrix[1][1] + tz * m_matrix[2][1];
928 m_matrix[3][2] += tx * m_matrix[0][2] + ty * m_matrix[1][2] + tz * m_matrix[2][2];
929 m_matrix[3][3] += tx * m_matrix[0][3] + ty * m_matrix[1][3] + tz * m_matrix[2][3];
933 TransformationMatrix& TransformationMatrix::translateRight(double tx, double ty)
936 m_matrix[0][0] += m_matrix[0][3] * tx;
937 m_matrix[1][0] += m_matrix[1][3] * tx;
938 m_matrix[2][0] += m_matrix[2][3] * tx;
939 m_matrix[3][0] += m_matrix[3][3] * tx;
943 m_matrix[0][1] += m_matrix[0][3] * ty;
944 m_matrix[1][1] += m_matrix[1][3] * ty;
945 m_matrix[2][1] += m_matrix[2][3] * ty;
946 m_matrix[3][1] += m_matrix[3][3] * ty;
952 TransformationMatrix& TransformationMatrix::translateRight3d(double tx, double ty, double tz)
954 translateRight(tx, ty);
956 m_matrix[0][2] += m_matrix[0][3] * tz;
957 m_matrix[1][2] += m_matrix[1][3] * tz;
958 m_matrix[2][2] += m_matrix[2][3] * tz;
959 m_matrix[3][2] += m_matrix[3][3] * tz;
965 TransformationMatrix& TransformationMatrix::skew(double sx, double sy)
967 // angles are in degrees. Switch to radians
971 TransformationMatrix mat;
972 mat.m_matrix[0][1] = tan(sy); // note that the y shear goes in the first row
973 mat.m_matrix[1][0] = tan(sx); // and the x shear in the second row
979 TransformationMatrix& TransformationMatrix::applyPerspective(double p)
981 TransformationMatrix mat;
983 mat.m_matrix[2][3] = -1/p;
989 TransformationMatrix TransformationMatrix::rectToRect(const FloatRect& from, const FloatRect& to)
991 ASSERT(!from.isEmpty());
992 return TransformationMatrix(to.width() / from.width(),
994 to.height() / from.height(),
999 // this = mat * this.
1000 TransformationMatrix& TransformationMatrix::multiply(const TransformationMatrix& mat)
1002 #if CPU(APPLE_ARMV7S)
1003 double* leftMatrix = &(m_matrix[0][0]);
1004 const double* rightMatrix = &(mat.m_matrix[0][0]);
1005 asm volatile (// First row of leftMatrix.
1006 "mov r3, %[leftMatrix]\n\t"
1007 "vld1.64 { d16-d19 }, [%[leftMatrix], :128]!\n\t"
1008 "vld1.64 { d0-d3}, [%[rightMatrix], :128]!\n\t"
1009 "vmul.f64 d4, d0, d16\n\t"
1010 "vld1.64 { d20-d23 }, [%[leftMatrix], :128]!\n\t"
1011 "vmla.f64 d4, d1, d20\n\t"
1012 "vld1.64 { d24-d27 }, [%[leftMatrix], :128]!\n\t"
1013 "vmla.f64 d4, d2, d24\n\t"
1014 "vld1.64 { d28-d31 }, [%[leftMatrix], :128]!\n\t"
1015 "vmla.f64 d4, d3, d28\n\t"
1017 "vmul.f64 d5, d0, d17\n\t"
1018 "vmla.f64 d5, d1, d21\n\t"
1019 "vmla.f64 d5, d2, d25\n\t"
1020 "vmla.f64 d5, d3, d29\n\t"
1022 "vmul.f64 d6, d0, d18\n\t"
1023 "vmla.f64 d6, d1, d22\n\t"
1024 "vmla.f64 d6, d2, d26\n\t"
1025 "vmla.f64 d6, d3, d30\n\t"
1027 "vmul.f64 d7, d0, d19\n\t"
1028 "vmla.f64 d7, d1, d23\n\t"
1029 "vmla.f64 d7, d2, d27\n\t"
1030 "vmla.f64 d7, d3, d31\n\t"
1031 "vld1.64 { d0-d3}, [%[rightMatrix], :128]!\n\t"
1032 "vst1.64 { d4-d7 }, [r3, :128]!\n\t"
1034 // Second row of leftMatrix.
1035 "vmul.f64 d4, d0, d16\n\t"
1036 "vmla.f64 d4, d1, d20\n\t"
1037 "vmla.f64 d4, d2, d24\n\t"
1038 "vmla.f64 d4, d3, d28\n\t"
1040 "vmul.f64 d5, d0, d17\n\t"
1041 "vmla.f64 d5, d1, d21\n\t"
1042 "vmla.f64 d5, d2, d25\n\t"
1043 "vmla.f64 d5, d3, d29\n\t"
1045 "vmul.f64 d6, d0, d18\n\t"
1046 "vmla.f64 d6, d1, d22\n\t"
1047 "vmla.f64 d6, d2, d26\n\t"
1048 "vmla.f64 d6, d3, d30\n\t"
1050 "vmul.f64 d7, d0, d19\n\t"
1051 "vmla.f64 d7, d1, d23\n\t"
1052 "vmla.f64 d7, d2, d27\n\t"
1053 "vmla.f64 d7, d3, d31\n\t"
1054 "vld1.64 { d0-d3}, [%[rightMatrix], :128]!\n\t"
1055 "vst1.64 { d4-d7 }, [r3, :128]!\n\t"
1057 // Third row of leftMatrix.
1058 "vmul.f64 d4, d0, d16\n\t"
1059 "vmla.f64 d4, d1, d20\n\t"
1060 "vmla.f64 d4, d2, d24\n\t"
1061 "vmla.f64 d4, d3, d28\n\t"
1063 "vmul.f64 d5, d0, d17\n\t"
1064 "vmla.f64 d5, d1, d21\n\t"
1065 "vmla.f64 d5, d2, d25\n\t"
1066 "vmla.f64 d5, d3, d29\n\t"
1068 "vmul.f64 d6, d0, d18\n\t"
1069 "vmla.f64 d6, d1, d22\n\t"
1070 "vmla.f64 d6, d2, d26\n\t"
1071 "vmla.f64 d6, d3, d30\n\t"
1073 "vmul.f64 d7, d0, d19\n\t"
1074 "vmla.f64 d7, d1, d23\n\t"
1075 "vmla.f64 d7, d2, d27\n\t"
1076 "vmla.f64 d7, d3, d31\n\t"
1077 "vld1.64 { d0-d3}, [%[rightMatrix], :128]\n\t"
1078 "vst1.64 { d4-d7 }, [r3, :128]!\n\t"
1080 // Fourth and last row of leftMatrix.
1081 "vmul.f64 d4, d0, d16\n\t"
1082 "vmla.f64 d4, d1, d20\n\t"
1083 "vmla.f64 d4, d2, d24\n\t"
1084 "vmla.f64 d4, d3, d28\n\t"
1086 "vmul.f64 d5, d0, d17\n\t"
1087 "vmla.f64 d5, d1, d21\n\t"
1088 "vmla.f64 d5, d2, d25\n\t"
1089 "vmla.f64 d5, d3, d29\n\t"
1091 "vmul.f64 d6, d0, d18\n\t"
1092 "vmla.f64 d6, d1, d22\n\t"
1093 "vmla.f64 d6, d2, d26\n\t"
1094 "vmla.f64 d6, d3, d30\n\t"
1096 "vmul.f64 d7, d0, d19\n\t"
1097 "vmla.f64 d7, d1, d23\n\t"
1098 "vmla.f64 d7, d2, d27\n\t"
1099 "vmla.f64 d7, d3, d31\n\t"
1100 "vst1.64 { d4-d7 }, [r3, :128]\n\t"
1101 : [leftMatrix]"+r"(leftMatrix), [rightMatrix]"+r"(rightMatrix)
1103 : "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");
1104 #elif defined(TRANSFORMATION_MATRIX_USE_X86_64_SSE2)
1105 // x86_64 has 16 XMM registers which is enough to do the multiplication fully in registers.
1106 __m128d matrixBlockA = _mm_load_pd(&(m_matrix[0][0]));
1107 __m128d matrixBlockC = _mm_load_pd(&(m_matrix[1][0]));
1108 __m128d matrixBlockE = _mm_load_pd(&(m_matrix[2][0]));
1109 __m128d matrixBlockG = _mm_load_pd(&(m_matrix[3][0]));
1112 __m128d otherMatrixFirstParam = _mm_set1_pd(mat.m_matrix[0][0]);
1113 __m128d otherMatrixSecondParam = _mm_set1_pd(mat.m_matrix[0][1]);
1114 __m128d otherMatrixThirdParam = _mm_set1_pd(mat.m_matrix[0][2]);
1115 __m128d otherMatrixFourthParam = _mm_set1_pd(mat.m_matrix[0][3]);
1117 // output00 and output01.
1118 __m128d accumulator = _mm_mul_pd(matrixBlockA, otherMatrixFirstParam);
1119 __m128d temp1 = _mm_mul_pd(matrixBlockC, otherMatrixSecondParam);
1120 __m128d temp2 = _mm_mul_pd(matrixBlockE, otherMatrixThirdParam);
1121 __m128d temp3 = _mm_mul_pd(matrixBlockG, otherMatrixFourthParam);
1123 __m128d matrixBlockB = _mm_load_pd(&(m_matrix[0][2]));
1124 __m128d matrixBlockD = _mm_load_pd(&(m_matrix[1][2]));
1125 __m128d matrixBlockF = _mm_load_pd(&(m_matrix[2][2]));
1126 __m128d matrixBlockH = _mm_load_pd(&(m_matrix[3][2]));
1128 accumulator = _mm_add_pd(accumulator, temp1);
1129 accumulator = _mm_add_pd(accumulator, temp2);
1130 accumulator = _mm_add_pd(accumulator, temp3);
1131 _mm_store_pd(&m_matrix[0][0], accumulator);
1133 // output02 and output03.
1134 accumulator = _mm_mul_pd(matrixBlockB, otherMatrixFirstParam);
1135 temp1 = _mm_mul_pd(matrixBlockD, otherMatrixSecondParam);
1136 temp2 = _mm_mul_pd(matrixBlockF, otherMatrixThirdParam);
1137 temp3 = _mm_mul_pd(matrixBlockH, otherMatrixFourthParam);
1139 accumulator = _mm_add_pd(accumulator, temp1);
1140 accumulator = _mm_add_pd(accumulator, temp2);
1141 accumulator = _mm_add_pd(accumulator, temp3);
1142 _mm_store_pd(&m_matrix[0][2], accumulator);
1145 otherMatrixFirstParam = _mm_set1_pd(mat.m_matrix[1][0]);
1146 otherMatrixSecondParam = _mm_set1_pd(mat.m_matrix[1][1]);
1147 otherMatrixThirdParam = _mm_set1_pd(mat.m_matrix[1][2]);
1148 otherMatrixFourthParam = _mm_set1_pd(mat.m_matrix[1][3]);
1150 // output10 and output11.
1151 accumulator = _mm_mul_pd(matrixBlockA, otherMatrixFirstParam);
1152 temp1 = _mm_mul_pd(matrixBlockC, otherMatrixSecondParam);
1153 temp2 = _mm_mul_pd(matrixBlockE, otherMatrixThirdParam);
1154 temp3 = _mm_mul_pd(matrixBlockG, otherMatrixFourthParam);
1156 accumulator = _mm_add_pd(accumulator, temp1);
1157 accumulator = _mm_add_pd(accumulator, temp2);
1158 accumulator = _mm_add_pd(accumulator, temp3);
1159 _mm_store_pd(&m_matrix[1][0], accumulator);
1161 // output12 and output13.
1162 accumulator = _mm_mul_pd(matrixBlockB, otherMatrixFirstParam);
1163 temp1 = _mm_mul_pd(matrixBlockD, otherMatrixSecondParam);
1164 temp2 = _mm_mul_pd(matrixBlockF, otherMatrixThirdParam);
1165 temp3 = _mm_mul_pd(matrixBlockH, otherMatrixFourthParam);
1167 accumulator = _mm_add_pd(accumulator, temp1);
1168 accumulator = _mm_add_pd(accumulator, temp2);
1169 accumulator = _mm_add_pd(accumulator, temp3);
1170 _mm_store_pd(&m_matrix[1][2], accumulator);
1173 otherMatrixFirstParam = _mm_set1_pd(mat.m_matrix[2][0]);
1174 otherMatrixSecondParam = _mm_set1_pd(mat.m_matrix[2][1]);
1175 otherMatrixThirdParam = _mm_set1_pd(mat.m_matrix[2][2]);
1176 otherMatrixFourthParam = _mm_set1_pd(mat.m_matrix[2][3]);
1178 // output20 and output21.
1179 accumulator = _mm_mul_pd(matrixBlockA, otherMatrixFirstParam);
1180 temp1 = _mm_mul_pd(matrixBlockC, otherMatrixSecondParam);
1181 temp2 = _mm_mul_pd(matrixBlockE, otherMatrixThirdParam);
1182 temp3 = _mm_mul_pd(matrixBlockG, otherMatrixFourthParam);
1184 accumulator = _mm_add_pd(accumulator, temp1);
1185 accumulator = _mm_add_pd(accumulator, temp2);
1186 accumulator = _mm_add_pd(accumulator, temp3);
1187 _mm_store_pd(&m_matrix[2][0], accumulator);
1189 // output22 and output23.
1190 accumulator = _mm_mul_pd(matrixBlockB, otherMatrixFirstParam);
1191 temp1 = _mm_mul_pd(matrixBlockD, otherMatrixSecondParam);
1192 temp2 = _mm_mul_pd(matrixBlockF, otherMatrixThirdParam);
1193 temp3 = _mm_mul_pd(matrixBlockH, otherMatrixFourthParam);
1195 accumulator = _mm_add_pd(accumulator, temp1);
1196 accumulator = _mm_add_pd(accumulator, temp2);
1197 accumulator = _mm_add_pd(accumulator, temp3);
1198 _mm_store_pd(&m_matrix[2][2], accumulator);
1201 otherMatrixFirstParam = _mm_set1_pd(mat.m_matrix[3][0]);
1202 otherMatrixSecondParam = _mm_set1_pd(mat.m_matrix[3][1]);
1203 otherMatrixThirdParam = _mm_set1_pd(mat.m_matrix[3][2]);
1204 otherMatrixFourthParam = _mm_set1_pd(mat.m_matrix[3][3]);
1206 // output30 and output31.
1207 accumulator = _mm_mul_pd(matrixBlockA, otherMatrixFirstParam);
1208 temp1 = _mm_mul_pd(matrixBlockC, otherMatrixSecondParam);
1209 temp2 = _mm_mul_pd(matrixBlockE, otherMatrixThirdParam);
1210 temp3 = _mm_mul_pd(matrixBlockG, otherMatrixFourthParam);
1212 accumulator = _mm_add_pd(accumulator, temp1);
1213 accumulator = _mm_add_pd(accumulator, temp2);
1214 accumulator = _mm_add_pd(accumulator, temp3);
1215 _mm_store_pd(&m_matrix[3][0], accumulator);
1217 // output32 and output33.
1218 accumulator = _mm_mul_pd(matrixBlockB, otherMatrixFirstParam);
1219 temp1 = _mm_mul_pd(matrixBlockD, otherMatrixSecondParam);
1220 temp2 = _mm_mul_pd(matrixBlockF, otherMatrixThirdParam);
1221 temp3 = _mm_mul_pd(matrixBlockH, otherMatrixFourthParam);
1223 accumulator = _mm_add_pd(accumulator, temp1);
1224 accumulator = _mm_add_pd(accumulator, temp2);
1225 accumulator = _mm_add_pd(accumulator, temp3);
1226 _mm_store_pd(&m_matrix[3][2], accumulator);
1230 tmp[0][0] = (mat.m_matrix[0][0] * m_matrix[0][0] + mat.m_matrix[0][1] * m_matrix[1][0]
1231 + mat.m_matrix[0][2] * m_matrix[2][0] + mat.m_matrix[0][3] * m_matrix[3][0]);
1232 tmp[0][1] = (mat.m_matrix[0][0] * m_matrix[0][1] + mat.m_matrix[0][1] * m_matrix[1][1]
1233 + mat.m_matrix[0][2] * m_matrix[2][1] + mat.m_matrix[0][3] * m_matrix[3][1]);
1234 tmp[0][2] = (mat.m_matrix[0][0] * m_matrix[0][2] + mat.m_matrix[0][1] * m_matrix[1][2]
1235 + mat.m_matrix[0][2] * m_matrix[2][2] + mat.m_matrix[0][3] * m_matrix[3][2]);
1236 tmp[0][3] = (mat.m_matrix[0][0] * m_matrix[0][3] + mat.m_matrix[0][1] * m_matrix[1][3]
1237 + mat.m_matrix[0][2] * m_matrix[2][3] + mat.m_matrix[0][3] * m_matrix[3][3]);
1239 tmp[1][0] = (mat.m_matrix[1][0] * m_matrix[0][0] + mat.m_matrix[1][1] * m_matrix[1][0]
1240 + mat.m_matrix[1][2] * m_matrix[2][0] + mat.m_matrix[1][3] * m_matrix[3][0]);
1241 tmp[1][1] = (mat.m_matrix[1][0] * m_matrix[0][1] + mat.m_matrix[1][1] * m_matrix[1][1]
1242 + mat.m_matrix[1][2] * m_matrix[2][1] + mat.m_matrix[1][3] * m_matrix[3][1]);
1243 tmp[1][2] = (mat.m_matrix[1][0] * m_matrix[0][2] + mat.m_matrix[1][1] * m_matrix[1][2]
1244 + mat.m_matrix[1][2] * m_matrix[2][2] + mat.m_matrix[1][3] * m_matrix[3][2]);
1245 tmp[1][3] = (mat.m_matrix[1][0] * m_matrix[0][3] + mat.m_matrix[1][1] * m_matrix[1][3]
1246 + mat.m_matrix[1][2] * m_matrix[2][3] + mat.m_matrix[1][3] * m_matrix[3][3]);
1248 tmp[2][0] = (mat.m_matrix[2][0] * m_matrix[0][0] + mat.m_matrix[2][1] * m_matrix[1][0]
1249 + mat.m_matrix[2][2] * m_matrix[2][0] + mat.m_matrix[2][3] * m_matrix[3][0]);
1250 tmp[2][1] = (mat.m_matrix[2][0] * m_matrix[0][1] + mat.m_matrix[2][1] * m_matrix[1][1]
1251 + mat.m_matrix[2][2] * m_matrix[2][1] + mat.m_matrix[2][3] * m_matrix[3][1]);
1252 tmp[2][2] = (mat.m_matrix[2][0] * m_matrix[0][2] + mat.m_matrix[2][1] * m_matrix[1][2]
1253 + mat.m_matrix[2][2] * m_matrix[2][2] + mat.m_matrix[2][3] * m_matrix[3][2]);
1254 tmp[2][3] = (mat.m_matrix[2][0] * m_matrix[0][3] + mat.m_matrix[2][1] * m_matrix[1][3]
1255 + mat.m_matrix[2][2] * m_matrix[2][3] + mat.m_matrix[2][3] * m_matrix[3][3]);
1257 tmp[3][0] = (mat.m_matrix[3][0] * m_matrix[0][0] + mat.m_matrix[3][1] * m_matrix[1][0]
1258 + mat.m_matrix[3][2] * m_matrix[2][0] + mat.m_matrix[3][3] * m_matrix[3][0]);
1259 tmp[3][1] = (mat.m_matrix[3][0] * m_matrix[0][1] + mat.m_matrix[3][1] * m_matrix[1][1]
1260 + mat.m_matrix[3][2] * m_matrix[2][1] + mat.m_matrix[3][3] * m_matrix[3][1]);
1261 tmp[3][2] = (mat.m_matrix[3][0] * m_matrix[0][2] + mat.m_matrix[3][1] * m_matrix[1][2]
1262 + mat.m_matrix[3][2] * m_matrix[2][2] + mat.m_matrix[3][3] * m_matrix[3][2]);
1263 tmp[3][3] = (mat.m_matrix[3][0] * m_matrix[0][3] + mat.m_matrix[3][1] * m_matrix[1][3]
1264 + mat.m_matrix[3][2] * m_matrix[2][3] + mat.m_matrix[3][3] * m_matrix[3][3]);
1271 void TransformationMatrix::multVecMatrix(double x, double y, double& resultX, double& resultY) const
1273 resultX = m_matrix[3][0] + x * m_matrix[0][0] + y * m_matrix[1][0];
1274 resultY = m_matrix[3][1] + x * m_matrix[0][1] + y * m_matrix[1][1];
1275 double w = m_matrix[3][3] + x * m_matrix[0][3] + y * m_matrix[1][3];
1276 if (w != 1 && w != 0) {
1282 void TransformationMatrix::multVecMatrix(double x, double y, double z, double& resultX, double& resultY, double& resultZ) const
1284 resultX = m_matrix[3][0] + x * m_matrix[0][0] + y * m_matrix[1][0] + z * m_matrix[2][0];
1285 resultY = m_matrix[3][1] + x * m_matrix[0][1] + y * m_matrix[1][1] + z * m_matrix[2][1];
1286 resultZ = m_matrix[3][2] + x * m_matrix[0][2] + y * m_matrix[1][2] + z * m_matrix[2][2];
1287 double w = m_matrix[3][3] + x * m_matrix[0][3] + y * m_matrix[1][3] + z * m_matrix[2][3];
1288 if (w != 1 && w != 0) {
1295 bool TransformationMatrix::isInvertible() const
1297 if (isIdentityOrTranslation())
1300 double det = WebCore::determinant4x4(m_matrix);
1302 if (fabs(det) < SMALL_NUMBER)
1308 TransformationMatrix TransformationMatrix::inverse() const
1310 if (isIdentityOrTranslation()) {
1312 if (m_matrix[3][0] == 0 && m_matrix[3][1] == 0 && m_matrix[3][2] == 0)
1313 return TransformationMatrix();
1316 return TransformationMatrix(1, 0, 0, 0,
1319 -m_matrix[3][0], -m_matrix[3][1], -m_matrix[3][2], 1);
1322 TransformationMatrix invMat;
1323 bool inverted = WebCore::inverse(m_matrix, invMat.m_matrix);
1325 return TransformationMatrix();
1330 void TransformationMatrix::makeAffine()
1347 AffineTransform TransformationMatrix::toAffineTransform() const
1349 return AffineTransform(m_matrix[0][0], m_matrix[0][1], m_matrix[1][0],
1350 m_matrix[1][1], m_matrix[3][0], m_matrix[3][1]);
1353 static inline void blendFloat(double& from, double to, double progress)
1356 from = from + (to - from) * progress;
1359 void TransformationMatrix::blend(const TransformationMatrix& from, double progress)
1361 if (from.isIdentity() && isIdentity())
1365 DecomposedType fromDecomp;
1366 DecomposedType toDecomp;
1367 if (!from.decompose(fromDecomp) || !decompose(toDecomp)) {
1374 blendFloat(fromDecomp.scaleX, toDecomp.scaleX, progress);
1375 blendFloat(fromDecomp.scaleY, toDecomp.scaleY, progress);
1376 blendFloat(fromDecomp.scaleZ, toDecomp.scaleZ, progress);
1377 blendFloat(fromDecomp.skewXY, toDecomp.skewXY, progress);
1378 blendFloat(fromDecomp.skewXZ, toDecomp.skewXZ, progress);
1379 blendFloat(fromDecomp.skewYZ, toDecomp.skewYZ, progress);
1380 blendFloat(fromDecomp.translateX, toDecomp.translateX, progress);
1381 blendFloat(fromDecomp.translateY, toDecomp.translateY, progress);
1382 blendFloat(fromDecomp.translateZ, toDecomp.translateZ, progress);
1383 blendFloat(fromDecomp.perspectiveX, toDecomp.perspectiveX, progress);
1384 blendFloat(fromDecomp.perspectiveY, toDecomp.perspectiveY, progress);
1385 blendFloat(fromDecomp.perspectiveZ, toDecomp.perspectiveZ, progress);
1386 blendFloat(fromDecomp.perspectiveW, toDecomp.perspectiveW, progress);
1388 slerp(&fromDecomp.quaternionX, &toDecomp.quaternionX, progress);
1391 recompose(fromDecomp);
1394 bool TransformationMatrix::decompose(DecomposedType& decomp) const
1397 memset(&decomp, 0, sizeof(decomp));
1398 decomp.perspectiveW = 1;
1404 if (!WebCore::decompose(m_matrix, decomp))
1409 void TransformationMatrix::recompose(const DecomposedType& decomp)
1413 // first apply perspective
1414 m_matrix[0][3] = decomp.perspectiveX;
1415 m_matrix[1][3] = decomp.perspectiveY;
1416 m_matrix[2][3] = decomp.perspectiveZ;
1417 m_matrix[3][3] = decomp.perspectiveW;
1420 translate3d(decomp.translateX, decomp.translateY, decomp.translateZ);
1423 double xx = decomp.quaternionX * decomp.quaternionX;
1424 double xy = decomp.quaternionX * decomp.quaternionY;
1425 double xz = decomp.quaternionX * decomp.quaternionZ;
1426 double xw = decomp.quaternionX * decomp.quaternionW;
1427 double yy = decomp.quaternionY * decomp.quaternionY;
1428 double yz = decomp.quaternionY * decomp.quaternionZ;
1429 double yw = decomp.quaternionY * decomp.quaternionW;
1430 double zz = decomp.quaternionZ * decomp.quaternionZ;
1431 double zw = decomp.quaternionZ * decomp.quaternionW;
1433 // Construct a composite rotation matrix from the quaternion values
1434 TransformationMatrix rotationMatrix(1 - 2 * (yy + zz), 2 * (xy - zw), 2 * (xz + yw), 0,
1435 2 * (xy + zw), 1 - 2 * (xx + zz), 2 * (yz - xw), 0,
1436 2 * (xz - yw), 2 * (yz + xw), 1 - 2 * (xx + yy), 0,
1439 multiply(rotationMatrix);
1442 if (decomp.skewYZ) {
1443 TransformationMatrix tmp;
1444 tmp.setM32(decomp.skewYZ);
1448 if (decomp.skewXZ) {
1449 TransformationMatrix tmp;
1450 tmp.setM31(decomp.skewXZ);
1454 if (decomp.skewXY) {
1455 TransformationMatrix tmp;
1456 tmp.setM21(decomp.skewXY);
1460 // finally, apply scale
1461 scale3d(decomp.scaleX, decomp.scaleY, decomp.scaleZ);
1464 bool TransformationMatrix::isIntegerTranslation() const
1466 if (!isIdentityOrTranslation())
1469 // Check for translate Z.
1473 // Check for non-integer translate X/Y.
1474 if (static_cast<int>(m_matrix[3][0]) != m_matrix[3][0] || static_cast<int>(m_matrix[3][1]) != m_matrix[3][1])
1480 TransformationMatrix TransformationMatrix::to2dTransform() const
1482 return TransformationMatrix(m_matrix[0][0], m_matrix[0][1], 0, m_matrix[0][3],
1483 m_matrix[1][0], m_matrix[1][1], 0, m_matrix[1][3],
1485 m_matrix[3][0], m_matrix[3][1], 0, m_matrix[3][3]);
1488 void TransformationMatrix::toColumnMajorFloatArray(FloatMatrix4& result) const
1508 bool TransformationMatrix::isBackFaceVisible() const
1510 // Back-face visibility is determined by transforming the normal vector (0, 0, 1) and
1511 // checking the sign of the resulting z component. However, normals cannot be
1512 // transformed by the original matrix, they require being transformed by the
1513 // inverse-transpose.
1515 // Since we know we will be using (0, 0, 1), and we only care about the z-component of
1516 // the transformed normal, then we only need the m33() element of the
1517 // inverse-transpose. Therefore we do not need the transpose.
1519 // Additionally, if we only need the m33() element, we do not need to compute a full
1520 // inverse. Instead, knowing the inverse of a matrix is adjoint(matrix) / determinant,
1521 // we can simply compute the m33() of the adjoint (adjugate) matrix, without computing
1522 // the full adjoint.
1524 double determinant = WebCore::determinant4x4(m_matrix);
1526 // If the matrix is not invertible, then we assume its backface is not visible.
1527 if (fabs(determinant) < SMALL_NUMBER)
1530 double cofactor33 = determinant3x3(m11(), m12(), m14(), m21(), m22(), m24(), m41(), m42(), m44());
1531 double zComponentOfTransformedNormal = cofactor33 / determinant;
1533 return zComponentOfTransformedNormal < 0;
1536 SkMatrix44 TransformationMatrix::toSkMatrix44(const TransformationMatrix& matrix)
1538 SkMatrix44 ret(SkMatrix44::kUninitialized_Constructor);
1539 ret.setDouble(0, 0, matrix.m11());
1540 ret.setDouble(0, 1, matrix.m21());
1541 ret.setDouble(0, 2, matrix.m31());
1542 ret.setDouble(0, 3, matrix.m41());
1543 ret.setDouble(1, 0, matrix.m12());
1544 ret.setDouble(1, 1, matrix.m22());
1545 ret.setDouble(1, 2, matrix.m32());
1546 ret.setDouble(1, 3, matrix.m42());
1547 ret.setDouble(2, 0, matrix.m13());
1548 ret.setDouble(2, 1, matrix.m23());
1549 ret.setDouble(2, 2, matrix.m33());
1550 ret.setDouble(2, 3, matrix.m43());
1551 ret.setDouble(3, 0, matrix.m14());
1552 ret.setDouble(3, 1, matrix.m24());
1553 ret.setDouble(3, 2, matrix.m34());
1554 ret.setDouble(3, 3, matrix.m44());