1/* 2 * Copyright (C) 2005, 2006 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#ifndef TransformationMatrix_h 27#define TransformationMatrix_h 28 29#include "FloatPoint.h" 30#include "FloatPoint3D.h" 31#include "IntPoint.h" 32#include <string.h> //for memcpy 33#include <wtf/FastMalloc.h> 34 35#if USE(CA) 36typedef struct CATransform3D CATransform3D; 37#endif 38#if USE(CG) 39typedef struct CGAffineTransform CGAffineTransform; 40#elif USE(CAIRO) 41#include <cairo.h> 42#endif 43 44#if PLATFORM(WIN) || (PLATFORM(GTK) && OS(WINDOWS)) 45#if COMPILER(MINGW) && !COMPILER(MINGW64) 46typedef struct _XFORM XFORM; 47#else 48typedef struct tagXFORM XFORM; 49#endif 50#endif 51 52namespace WebCore { 53 54class AffineTransform; 55class IntRect; 56class LayoutRect; 57class FloatRect; 58class FloatQuad; 59 60#if CPU(X86_64) 61#define TRANSFORMATION_MATRIX_USE_X86_64_SSE2 62#endif 63 64class TransformationMatrix { 65 WTF_MAKE_FAST_ALLOCATED; 66public: 67 68#if CPU(APPLE_ARMV7S) || defined(TRANSFORMATION_MATRIX_USE_X86_64_SSE2) 69#if COMPILER(MSVC) 70 __declspec(align(16)) typedef double Matrix4[4][4]; 71#else 72 typedef double Matrix4[4][4] __attribute__((aligned (16))); 73#endif 74#else 75 typedef double Matrix4[4][4]; 76#endif 77 78 TransformationMatrix() { makeIdentity(); } 79 TransformationMatrix(const AffineTransform& t); 80 TransformationMatrix(const TransformationMatrix& t) { *this = t; } 81 TransformationMatrix(double a, double b, double c, double d, double e, double f) { setMatrix(a, b, c, d, e, f); } 82 TransformationMatrix(double m11, double m12, double m13, double m14, 83 double m21, double m22, double m23, double m24, 84 double m31, double m32, double m33, double m34, 85 double m41, double m42, double m43, double m44) 86 { 87 setMatrix(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44); 88 } 89 90 void setMatrix(double a, double b, double c, double d, double e, double f) 91 { 92 m_matrix[0][0] = a; m_matrix[0][1] = b; m_matrix[0][2] = 0; m_matrix[0][3] = 0; 93 m_matrix[1][0] = c; m_matrix[1][1] = d; m_matrix[1][2] = 0; m_matrix[1][3] = 0; 94 m_matrix[2][0] = 0; m_matrix[2][1] = 0; m_matrix[2][2] = 1; m_matrix[2][3] = 0; 95 m_matrix[3][0] = e; m_matrix[3][1] = f; m_matrix[3][2] = 0; m_matrix[3][3] = 1; 96 } 97 98 void setMatrix(double m11, double m12, double m13, double m14, 99 double m21, double m22, double m23, double m24, 100 double m31, double m32, double m33, double m34, 101 double m41, double m42, double m43, double m44) 102 { 103 m_matrix[0][0] = m11; m_matrix[0][1] = m12; m_matrix[0][2] = m13; m_matrix[0][3] = m14; 104 m_matrix[1][0] = m21; m_matrix[1][1] = m22; m_matrix[1][2] = m23; m_matrix[1][3] = m24; 105 m_matrix[2][0] = m31; m_matrix[2][1] = m32; m_matrix[2][2] = m33; m_matrix[2][3] = m34; 106 m_matrix[3][0] = m41; m_matrix[3][1] = m42; m_matrix[3][2] = m43; m_matrix[3][3] = m44; 107 } 108 109 TransformationMatrix& operator =(const TransformationMatrix &t) 110 { 111 setMatrix(t.m_matrix); 112 return *this; 113 } 114 115 TransformationMatrix& makeIdentity() 116 { 117 setMatrix(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 118 return *this; 119 } 120 121 bool isIdentity() const 122 { 123 return m_matrix[0][0] == 1 && m_matrix[0][1] == 0 && m_matrix[0][2] == 0 && m_matrix[0][3] == 0 && 124 m_matrix[1][0] == 0 && m_matrix[1][1] == 1 && m_matrix[1][2] == 0 && m_matrix[1][3] == 0 && 125 m_matrix[2][0] == 0 && m_matrix[2][1] == 0 && m_matrix[2][2] == 1 && m_matrix[2][3] == 0 && 126 m_matrix[3][0] == 0 && m_matrix[3][1] == 0 && m_matrix[3][2] == 0 && m_matrix[3][3] == 1; 127 } 128 129 // This form preserves the double math from input to output. 130 void map(double x, double y, double& x2, double& y2) const { multVecMatrix(x, y, x2, y2); } 131 132 // Maps a 3D point through the transform, returning a 3D point. 133 FloatPoint3D mapPoint(const FloatPoint3D&) const; 134 135 // Maps a 2D point through the transform, returning a 2D point. 136 // Note that this ignores the z component, effectively projecting the point into the z=0 plane. 137 FloatPoint mapPoint(const FloatPoint&) const; 138 139 // Like the version above, except that it rounds the mapped point to the nearest integer value. 140 IntPoint mapPoint(const IntPoint& p) const 141 { 142 return roundedIntPoint(mapPoint(FloatPoint(p))); 143 } 144 145 // If the matrix has 3D components, the z component of the result is 146 // dropped, effectively projecting the rect into the z=0 plane. 147 FloatRect mapRect(const FloatRect&) const; 148 149 // Rounds the resulting mapped rectangle out. This is helpful for bounding 150 // box computations but may not be what is wanted in other contexts. 151 IntRect mapRect(const IntRect&) const; 152 LayoutRect mapRect(const LayoutRect&) const; 153 154 // If the matrix has 3D components, the z component of the result is 155 // dropped, effectively projecting the quad into the z=0 plane. 156 FloatQuad mapQuad(const FloatQuad&) const; 157 158 // Maps a point on the z=0 plane into a point on the plane with with the transform applied, by 159 // extending a ray perpendicular to the source plane and computing the local x,y position of 160 // the point where that ray intersects with the destination plane. 161 FloatPoint projectPoint(const FloatPoint&, bool* clamped = 0) const; 162 // Projects the four corners of the quad. 163 FloatQuad projectQuad(const FloatQuad&, bool* clamped = 0) const; 164 // Projects the four corners of the quad and takes a bounding box, 165 // while sanitizing values created when the w component is negative. 166 LayoutRect clampedBoundsOfProjectedQuad(const FloatQuad&) const; 167 168 double m11() const { return m_matrix[0][0]; } 169 void setM11(double f) { m_matrix[0][0] = f; } 170 double m12() const { return m_matrix[0][1]; } 171 void setM12(double f) { m_matrix[0][1] = f; } 172 double m13() const { return m_matrix[0][2]; } 173 void setM13(double f) { m_matrix[0][2] = f; } 174 double m14() const { return m_matrix[0][3]; } 175 void setM14(double f) { m_matrix[0][3] = f; } 176 double m21() const { return m_matrix[1][0]; } 177 void setM21(double f) { m_matrix[1][0] = f; } 178 double m22() const { return m_matrix[1][1]; } 179 void setM22(double f) { m_matrix[1][1] = f; } 180 double m23() const { return m_matrix[1][2]; } 181 void setM23(double f) { m_matrix[1][2] = f; } 182 double m24() const { return m_matrix[1][3]; } 183 void setM24(double f) { m_matrix[1][3] = f; } 184 double m31() const { return m_matrix[2][0]; } 185 void setM31(double f) { m_matrix[2][0] = f; } 186 double m32() const { return m_matrix[2][1]; } 187 void setM32(double f) { m_matrix[2][1] = f; } 188 double m33() const { return m_matrix[2][2]; } 189 void setM33(double f) { m_matrix[2][2] = f; } 190 double m34() const { return m_matrix[2][3]; } 191 void setM34(double f) { m_matrix[2][3] = f; } 192 double m41() const { return m_matrix[3][0]; } 193 void setM41(double f) { m_matrix[3][0] = f; } 194 double m42() const { return m_matrix[3][1]; } 195 void setM42(double f) { m_matrix[3][1] = f; } 196 double m43() const { return m_matrix[3][2]; } 197 void setM43(double f) { m_matrix[3][2] = f; } 198 double m44() const { return m_matrix[3][3]; } 199 void setM44(double f) { m_matrix[3][3] = f; } 200 201 double a() const { return m_matrix[0][0]; } 202 void setA(double a) { m_matrix[0][0] = a; } 203 204 double b() const { return m_matrix[0][1]; } 205 void setB(double b) { m_matrix[0][1] = b; } 206 207 double c() const { return m_matrix[1][0]; } 208 void setC(double c) { m_matrix[1][0] = c; } 209 210 double d() const { return m_matrix[1][1]; } 211 void setD(double d) { m_matrix[1][1] = d; } 212 213 double e() const { return m_matrix[3][0]; } 214 void setE(double e) { m_matrix[3][0] = e; } 215 216 double f() const { return m_matrix[3][1]; } 217 void setF(double f) { m_matrix[3][1] = f; } 218 219 // this = mat * this. 220 TransformationMatrix& multiply(const TransformationMatrix&); 221 222 TransformationMatrix& scale(double); 223 TransformationMatrix& scaleNonUniform(double sx, double sy); 224 TransformationMatrix& scale3d(double sx, double sy, double sz); 225 226 // Angle is in degrees. 227 TransformationMatrix& rotate(double d) { return rotate3d(0, 0, d); } 228 TransformationMatrix& rotateFromVector(double x, double y); 229 TransformationMatrix& rotate3d(double rx, double ry, double rz); 230 231 // The vector (x,y,z) is normalized if it's not already. A vector of (0,0,0) uses a vector of (0,0,1). 232 TransformationMatrix& rotate3d(double x, double y, double z, double angle); 233 234 TransformationMatrix& translate(double tx, double ty); 235 TransformationMatrix& translate3d(double tx, double ty, double tz); 236 237 // translation added with a post-multiply 238 TransformationMatrix& translateRight(double tx, double ty); 239 TransformationMatrix& translateRight3d(double tx, double ty, double tz); 240 241 TransformationMatrix& flipX(); 242 TransformationMatrix& flipY(); 243 TransformationMatrix& skew(double angleX, double angleY); 244 TransformationMatrix& skewX(double angle) { return skew(angle, 0); } 245 TransformationMatrix& skewY(double angle) { return skew(0, angle); } 246 247 TransformationMatrix& applyPerspective(double p); 248 bool hasPerspective() const { return m_matrix[2][3] != 0.0f; } 249 250 // Returns a transformation that maps a rect to a rect. 251 static TransformationMatrix rectToRect(const FloatRect&, const FloatRect&); 252 253 bool isInvertible() const; 254 255 // Returns the identity matrix if it is not invertible. 256 // Use isInvertible() before calling this if you need to know. 257 TransformationMatrix inverse() const; 258 259 // Decompose the matrix into its component parts. 260 struct Decomposed2Type { 261 double scaleX, scaleY; 262 double translateX, translateY; 263 double angle; 264 double m11, m12, m21, m22; 265 266 bool operator==(const Decomposed2Type& other) const 267 { 268 return scaleX == other.scaleX && scaleY == other.scaleY 269 && translateX == other.translateX && translateY == other.translateY 270 && angle == other.angle 271 && m11 == other.m11 && m12 == other.m12 && m21 == other.m21 && m22 == other.m22; 272 } 273 }; 274 275 struct Decomposed4Type { 276 double scaleX, scaleY, scaleZ; 277 double skewXY, skewXZ, skewYZ; 278 double quaternionX, quaternionY, quaternionZ, quaternionW; 279 double translateX, translateY, translateZ; 280 double perspectiveX, perspectiveY, perspectiveZ, perspectiveW; 281 282 bool operator==(const Decomposed4Type& other) const 283 { 284 return scaleX == other.scaleX && scaleY == other.scaleY && scaleZ == other.scaleZ 285 && skewXY == other.skewXY && skewXZ == other.skewXZ && skewYZ == other.skewYZ 286 && quaternionX == other.quaternionX && quaternionY == other.quaternionY && quaternionZ == other.quaternionZ && quaternionW == other.quaternionW 287 && translateX == other.translateX && translateY == other.translateY && translateZ == other.translateZ 288 && perspectiveX == other.perspectiveX && perspectiveY == other.perspectiveY && perspectiveZ == other.perspectiveZ && perspectiveW == other.perspectiveW; 289 } 290 }; 291 292 bool decompose2(Decomposed2Type&) const; 293 void recompose2(const Decomposed2Type&); 294 295 bool decompose4(Decomposed4Type&) const; 296 void recompose4(const Decomposed4Type&); 297 298 void blend(const TransformationMatrix& from, double progress); 299 void blend2(const TransformationMatrix& from, double progress); 300 void blend4(const TransformationMatrix& from, double progress); 301 302 bool isAffine() const 303 { 304 return (m13() == 0 && m14() == 0 && m23() == 0 && m24() == 0 && 305 m31() == 0 && m32() == 0 && m33() == 1 && m34() == 0 && m43() == 0 && m44() == 1); 306 } 307 308 // Throw away the non-affine parts of the matrix (lossy!). 309 void makeAffine(); 310 311 AffineTransform toAffineTransform() const; 312 313 bool operator==(const TransformationMatrix& m2) const 314 { 315 return (m_matrix[0][0] == m2.m_matrix[0][0] && 316 m_matrix[0][1] == m2.m_matrix[0][1] && 317 m_matrix[0][2] == m2.m_matrix[0][2] && 318 m_matrix[0][3] == m2.m_matrix[0][3] && 319 m_matrix[1][0] == m2.m_matrix[1][0] && 320 m_matrix[1][1] == m2.m_matrix[1][1] && 321 m_matrix[1][2] == m2.m_matrix[1][2] && 322 m_matrix[1][3] == m2.m_matrix[1][3] && 323 m_matrix[2][0] == m2.m_matrix[2][0] && 324 m_matrix[2][1] == m2.m_matrix[2][1] && 325 m_matrix[2][2] == m2.m_matrix[2][2] && 326 m_matrix[2][3] == m2.m_matrix[2][3] && 327 m_matrix[3][0] == m2.m_matrix[3][0] && 328 m_matrix[3][1] == m2.m_matrix[3][1] && 329 m_matrix[3][2] == m2.m_matrix[3][2] && 330 m_matrix[3][3] == m2.m_matrix[3][3]); 331 } 332 333 bool operator!=(const TransformationMatrix& other) const { return !(*this == other); } 334 335 // *this = *this * t 336 TransformationMatrix& operator*=(const TransformationMatrix& t) 337 { 338 return multiply(t); 339 } 340 341 // result = *this * t 342 TransformationMatrix operator*(const TransformationMatrix& t) const 343 { 344 TransformationMatrix result = *this; 345 result.multiply(t); 346 return result; 347 } 348 349#if USE(CA) 350 TransformationMatrix(const CATransform3D&); 351 operator CATransform3D() const; 352#endif 353#if USE(CG) 354 TransformationMatrix(const CGAffineTransform&); 355 operator CGAffineTransform() const; 356#elif USE(CAIRO) 357 operator cairo_matrix_t() const; 358#endif 359 360#if PLATFORM(WIN) || (PLATFORM(GTK) && OS(WINDOWS)) 361 operator XFORM() const; 362#endif 363 364 bool isIdentityOrTranslation() const 365 { 366 return m_matrix[0][0] == 1 && m_matrix[0][1] == 0 && m_matrix[0][2] == 0 && m_matrix[0][3] == 0 367 && m_matrix[1][0] == 0 && m_matrix[1][1] == 1 && m_matrix[1][2] == 0 && m_matrix[1][3] == 0 368 && m_matrix[2][0] == 0 && m_matrix[2][1] == 0 && m_matrix[2][2] == 1 && m_matrix[2][3] == 0 369 && m_matrix[3][3] == 1; 370 } 371 372 bool isIntegerTranslation() const; 373 374 // Returns the matrix without 3D components. 375 TransformationMatrix to2dTransform() const; 376 377 typedef float FloatMatrix4[16]; 378 void toColumnMajorFloatArray(FloatMatrix4& result) const; 379 380 // A local-space layer is implicitly defined at the z = 0 plane, with its front side 381 // facing the positive z-axis (i.e. a camera looking along the negative z-axis sees 382 // the front side of the layer). This function checks if the transformed layer's back 383 // face would be visible to a camera looking along the negative z-axis in the target space. 384 bool isBackFaceVisible() const; 385 386private: 387 // multiply passed 2D point by matrix (assume z=0) 388 void multVecMatrix(double x, double y, double& dstX, double& dstY) const; 389 FloatPoint internalMapPoint(const FloatPoint& sourcePoint) const 390 { 391 double resultX; 392 double resultY; 393 multVecMatrix(sourcePoint.x(), sourcePoint.y(), resultX, resultY); 394 return FloatPoint(static_cast<float>(resultX), static_cast<float>(resultY)); 395 } 396 397 void multVecMatrix(double x, double y, double z, double& dstX, double& dstY, double& dstZ) const; 398 FloatPoint3D internalMapPoint(const FloatPoint3D& sourcePoint) const 399 { 400 double resultX; 401 double resultY; 402 double resultZ; 403 multVecMatrix(sourcePoint.x(), sourcePoint.y(), sourcePoint.z(), resultX, resultY, resultZ); 404 return FloatPoint3D(static_cast<float>(resultX), static_cast<float>(resultY), static_cast<float>(resultZ)); 405 } 406 407 void setMatrix(const Matrix4 m) 408 { 409 if (m && m != m_matrix) 410 memcpy(m_matrix, m, sizeof(Matrix4)); 411 } 412 413 Matrix4 m_matrix; 414}; 415 416} // namespace WebCore 417 418#endif // TransformationMatrix_h 419