1 /* 2 * Copyright (C) 2005, 2006 Apple Computer, 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 COMPUTER, 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 COMPUTER, 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 "IntPoint.h" 31 #include <string.h> //for memcpy 32 33 #if PLATFORM(CG) 34 #include <CoreGraphics/CGAffineTransform.h> 35 #elif PLATFORM(CAIRO) 36 #include <cairo.h> 37 #elif PLATFORM(QT) 38 #include <QTransform> 39 #elif PLATFORM(SKIA) || PLATFORM(SGL) 40 #include <SkMatrix.h> 41 #elif PLATFORM(WX) && USE(WXGC) 42 #include <wx/graphics.h> 43 #endif 44 45 namespace WebCore { 46 47 class IntRect; 48 class FloatPoint3D; 49 class FloatRect; 50 class FloatQuad; 51 52 class TransformationMatrix { 53 public: 54 typedef double Matrix4[4][4]; 55 TransformationMatrix()56 TransformationMatrix() { makeIdentity(); } TransformationMatrix(const TransformationMatrix & t)57 TransformationMatrix(const TransformationMatrix& t) { *this = t; } TransformationMatrix(double a,double b,double c,double d,double e,double f)58 TransformationMatrix(double a, double b, double c, double d, double e, double f) { setMatrix(a, b, c, d, e, f); } TransformationMatrix(double m11,double m12,double m13,double m14,double m21,double m22,double m23,double m24,double m31,double m32,double m33,double m34,double m41,double m42,double m43,double m44)59 TransformationMatrix(double m11, double m12, double m13, double m14, 60 double m21, double m22, double m23, double m24, 61 double m31, double m32, double m33, double m34, 62 double m41, double m42, double m43, double m44) 63 { 64 setMatrix(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44); 65 } 66 setMatrix(double a,double b,double c,double d,double e,double f)67 void setMatrix(double a, double b, double c, double d, double e, double f) 68 { 69 m_matrix[0][0] = a; m_matrix[0][1] = b; m_matrix[0][2] = 0; m_matrix[0][3] = 0; 70 m_matrix[1][0] = c; m_matrix[1][1] = d; m_matrix[1][2] = 0; m_matrix[1][3] = 0; 71 m_matrix[2][0] = 0; m_matrix[2][1] = 0; m_matrix[2][2] = 1; m_matrix[2][3] = 0; 72 m_matrix[3][0] = e; m_matrix[3][1] = f; m_matrix[3][2] = 0; m_matrix[3][3] = 1; 73 } 74 setMatrix(double m11,double m12,double m13,double m14,double m21,double m22,double m23,double m24,double m31,double m32,double m33,double m34,double m41,double m42,double m43,double m44)75 void setMatrix(double m11, double m12, double m13, double m14, 76 double m21, double m22, double m23, double m24, 77 double m31, double m32, double m33, double m34, 78 double m41, double m42, double m43, double m44) 79 { 80 m_matrix[0][0] = m11; m_matrix[0][1] = m12; m_matrix[0][2] = m13; m_matrix[0][3] = m14; 81 m_matrix[1][0] = m21; m_matrix[1][1] = m22; m_matrix[1][2] = m23; m_matrix[1][3] = m24; 82 m_matrix[2][0] = m31; m_matrix[2][1] = m32; m_matrix[2][2] = m33; m_matrix[2][3] = m34; 83 m_matrix[3][0] = m41; m_matrix[3][1] = m42; m_matrix[3][2] = m43; m_matrix[3][3] = m44; 84 } 85 86 TransformationMatrix& operator =(const TransformationMatrix &t) 87 { 88 setMatrix(t.m_matrix); 89 return *this; 90 } 91 makeIdentity()92 TransformationMatrix& makeIdentity() 93 { 94 setMatrix(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 95 return *this; 96 } 97 isIdentity()98 bool isIdentity() const 99 { 100 return m_matrix[0][0] == 1 && m_matrix[0][1] == 0 && m_matrix[0][2] == 0 && m_matrix[0][3] == 0 && 101 m_matrix[1][0] == 0 && m_matrix[1][1] == 1 && m_matrix[1][2] == 0 && m_matrix[1][3] == 0 && 102 m_matrix[2][0] == 0 && m_matrix[2][1] == 0 && m_matrix[2][2] == 1 && m_matrix[2][3] == 0 && 103 m_matrix[3][0] == 0 && m_matrix[3][1] == 0 && m_matrix[3][2] == 0 && m_matrix[3][3] == 1; 104 } 105 106 // This form preserves the double math from input to output map(double x,double y,double & x2,double & y2)107 void map(double x, double y, double& x2, double& y2) const { multVecMatrix(x, y, x2, y2); } 108 109 // Map a 3D point through the transform, returning a 3D point. 110 FloatPoint3D mapPoint(const FloatPoint3D&) const; 111 112 // Map a 2D point through the transform, returning a 2D point. 113 // Note that this ignores the z component, effectively projecting the point into the z=0 plane. 114 FloatPoint mapPoint(const FloatPoint&) const; 115 116 // Like the version above, except that it rounds the mapped point to the nearest integer value. mapPoint(const IntPoint & p)117 IntPoint mapPoint(const IntPoint& p) const 118 { 119 return roundedIntPoint(mapPoint(FloatPoint(p))); 120 } 121 122 // If the matrix has 3D components, the z component of the result is 123 // dropped, effectively projecting the rect into the z=0 plane 124 FloatRect mapRect(const FloatRect&) const; 125 126 // Rounds the resulting mapped rectangle out. This is helpful for bounding 127 // box computations but may not be what is wanted in other contexts. 128 IntRect mapRect(const IntRect&) const; 129 130 // If the matrix has 3D components, the z component of the result is 131 // dropped, effectively projecting the quad into the z=0 plane 132 FloatQuad mapQuad(const FloatQuad&) const; 133 134 // Map a point on the z=0 plane into a point on 135 // the plane with with the transform applied, by extending 136 // a ray perpendicular to the source plane and computing 137 // the local x,y position of the point where that ray intersects 138 // with the destination plane. 139 FloatPoint projectPoint(const FloatPoint&) const; 140 // Projects the four corners of the quad 141 FloatQuad projectQuad(const FloatQuad&) const; 142 m11()143 double m11() const { return m_matrix[0][0]; } setM11(double f)144 void setM11(double f) { m_matrix[0][0] = f; } m12()145 double m12() const { return m_matrix[0][1]; } setM12(double f)146 void setM12(double f) { m_matrix[0][1] = f; } m13()147 double m13() const { return m_matrix[0][2]; } setM13(double f)148 void setM13(double f) { m_matrix[0][2] = f; } m14()149 double m14() const { return m_matrix[0][3]; } setM14(double f)150 void setM14(double f) { m_matrix[0][3] = f; } m21()151 double m21() const { return m_matrix[1][0]; } setM21(double f)152 void setM21(double f) { m_matrix[1][0] = f; } m22()153 double m22() const { return m_matrix[1][1]; } setM22(double f)154 void setM22(double f) { m_matrix[1][1] = f; } m23()155 double m23() const { return m_matrix[1][2]; } setM23(double f)156 void setM23(double f) { m_matrix[1][2] = f; } m24()157 double m24() const { return m_matrix[1][3]; } setM24(double f)158 void setM24(double f) { m_matrix[1][3] = f; } m31()159 double m31() const { return m_matrix[2][0]; } setM31(double f)160 void setM31(double f) { m_matrix[2][0] = f; } m32()161 double m32() const { return m_matrix[2][1]; } setM32(double f)162 void setM32(double f) { m_matrix[2][1] = f; } m33()163 double m33() const { return m_matrix[2][2]; } setM33(double f)164 void setM33(double f) { m_matrix[2][2] = f; } m34()165 double m34() const { return m_matrix[2][3]; } setM34(double f)166 void setM34(double f) { m_matrix[2][3] = f; } m41()167 double m41() const { return m_matrix[3][0]; } setM41(double f)168 void setM41(double f) { m_matrix[3][0] = f; } m42()169 double m42() const { return m_matrix[3][1]; } setM42(double f)170 void setM42(double f) { m_matrix[3][1] = f; } m43()171 double m43() const { return m_matrix[3][2]; } setM43(double f)172 void setM43(double f) { m_matrix[3][2] = f; } m44()173 double m44() const { return m_matrix[3][3]; } setM44(double f)174 void setM44(double f) { m_matrix[3][3] = f; } 175 a()176 double a() const { return m_matrix[0][0]; } setA(double a)177 void setA(double a) { m_matrix[0][0] = a; } 178 b()179 double b() const { return m_matrix[0][1]; } setB(double b)180 void setB(double b) { m_matrix[0][1] = b; } 181 c()182 double c() const { return m_matrix[1][0]; } setC(double c)183 void setC(double c) { m_matrix[1][0] = c; } 184 d()185 double d() const { return m_matrix[1][1]; } setD(double d)186 void setD(double d) { m_matrix[1][1] = d; } 187 e()188 double e() const { return m_matrix[3][0]; } setE(double e)189 void setE(double e) { m_matrix[3][0] = e; } 190 f()191 double f() const { return m_matrix[3][1]; } setF(double f)192 void setF(double f) { m_matrix[3][1] = f; } 193 194 // this = this * mat multiply(const TransformationMatrix & t)195 TransformationMatrix& multiply(const TransformationMatrix& t) { return *this *= t; } 196 197 // this = mat * this 198 TransformationMatrix& multLeft(const TransformationMatrix& mat); 199 200 TransformationMatrix& scale(double); 201 TransformationMatrix& scaleNonUniform(double sx, double sy); 202 TransformationMatrix& scale3d(double sx, double sy, double sz); 203 rotate(double d)204 TransformationMatrix& rotate(double d) { return rotate3d(0, 0, d); } 205 TransformationMatrix& rotateFromVector(double x, double y); 206 TransformationMatrix& rotate3d(double rx, double ry, double rz); 207 208 // The vector (x,y,z) is normalized if it's not already. A vector of 209 // (0,0,0) uses a vector of (0,0,1). 210 TransformationMatrix& rotate3d(double x, double y, double z, double angle); 211 212 TransformationMatrix& translate(double tx, double ty); 213 TransformationMatrix& translate3d(double tx, double ty, double tz); 214 215 // translation added with a post-multiply 216 TransformationMatrix& translateRight(double tx, double ty); 217 TransformationMatrix& translateRight3d(double tx, double ty, double tz); 218 219 TransformationMatrix& flipX(); 220 TransformationMatrix& flipY(); 221 TransformationMatrix& skew(double angleX, double angleY); skewX(double angle)222 TransformationMatrix& skewX(double angle) { return skew(angle, 0); } skewY(double angle)223 TransformationMatrix& skewY(double angle) { return skew(0, angle); } 224 225 TransformationMatrix& applyPerspective(double p); hasPerspective()226 bool hasPerspective() const { return m_matrix[2][3] != 0.0f; } 227 228 // returns a transformation that maps a rect to a rect 229 static TransformationMatrix rectToRect(const FloatRect&, const FloatRect&); 230 231 bool isInvertible() const; 232 233 // This method returns the identity matrix if it is not invertible. 234 // Use isInvertible() before calling this if you need to know. 235 TransformationMatrix inverse() const; 236 237 // decompose the matrix into its component parts 238 typedef struct { 239 double scaleX, scaleY, scaleZ; 240 double skewXY, skewXZ, skewYZ; 241 double quaternionX, quaternionY, quaternionZ, quaternionW; 242 double translateX, translateY, translateZ; 243 double perspectiveX, perspectiveY, perspectiveZ, perspectiveW; 244 } DecomposedType; 245 246 bool decompose(DecomposedType& decomp) const; 247 void recompose(const DecomposedType& decomp); 248 249 void blend(const TransformationMatrix& from, double progress); 250 isAffine()251 bool isAffine() const 252 { 253 return (m13() == 0 && m14() == 0 && m23() == 0 && m24() == 0 && 254 m31() == 0 && m32() == 0 && m33() == 1 && m34() == 0 && m43() == 0 && m44() == 1); 255 } 256 257 // Throw away the non-affine parts of the matrix (lossy!) 258 void makeAffine(); 259 260 bool operator==(const TransformationMatrix& m2) const 261 { 262 return (m_matrix[0][0] == m2.m_matrix[0][0] && 263 m_matrix[0][1] == m2.m_matrix[0][1] && 264 m_matrix[0][2] == m2.m_matrix[0][2] && 265 m_matrix[0][3] == m2.m_matrix[0][3] && 266 m_matrix[1][0] == m2.m_matrix[1][0] && 267 m_matrix[1][1] == m2.m_matrix[1][1] && 268 m_matrix[1][2] == m2.m_matrix[1][2] && 269 m_matrix[1][3] == m2.m_matrix[1][3] && 270 m_matrix[2][0] == m2.m_matrix[2][0] && 271 m_matrix[2][1] == m2.m_matrix[2][1] && 272 m_matrix[2][2] == m2.m_matrix[2][2] && 273 m_matrix[2][3] == m2.m_matrix[2][3] && 274 m_matrix[3][0] == m2.m_matrix[3][0] && 275 m_matrix[3][1] == m2.m_matrix[3][1] && 276 m_matrix[3][2] == m2.m_matrix[3][2] && 277 m_matrix[3][3] == m2.m_matrix[3][3]); 278 } 279 280 bool operator!=(const TransformationMatrix& other) const { return !(*this == other); } 281 282 // *this = *this * t (i.e., a multRight) 283 TransformationMatrix& operator*=(const TransformationMatrix& t) 284 { 285 *this = *this * t; 286 return *this; 287 } 288 289 // result = *this * t (i.e., a multRight) 290 TransformationMatrix operator*(const TransformationMatrix& t) const 291 { 292 TransformationMatrix result = t; 293 result.multLeft(*this); 294 return result; 295 } 296 297 #if PLATFORM(CG) 298 operator CGAffineTransform() const; 299 #elif PLATFORM(CAIRO) 300 operator cairo_matrix_t() const; 301 #elif PLATFORM(QT) 302 operator QTransform() const; 303 #elif PLATFORM(SKIA) || PLATFORM(SGL) 304 operator SkMatrix() const; 305 #elif PLATFORM(WX) && USE(WXGC) 306 operator wxGraphicsMatrix() const; 307 #endif 308 309 #if PLATFORM(WIN) 310 operator XFORM() const; 311 #endif 312 313 private: 314 // multiply passed 2D point by matrix (assume z=0) 315 void multVecMatrix(double x, double y, double& dstX, double& dstY) const; 316 317 // multiply passed 3D point by matrix 318 void multVecMatrix(double x, double y, double z, double& dstX, double& dstY, double& dstZ) const; 319 setMatrix(const Matrix4 m)320 void setMatrix(const Matrix4 m) 321 { 322 if (m && m != m_matrix) 323 memcpy(m_matrix, m, sizeof(Matrix4)); 324 } 325 isIdentityOrTranslation()326 bool isIdentityOrTranslation() const 327 { 328 return m_matrix[0][0] == 1 && m_matrix[0][1] == 0 && m_matrix[0][2] == 0 && m_matrix[0][3] == 0 && 329 m_matrix[1][0] == 0 && m_matrix[1][1] == 1 && m_matrix[1][2] == 0 && m_matrix[1][3] == 0 && 330 m_matrix[2][0] == 0 && m_matrix[2][1] == 0 && m_matrix[2][2] == 1 && m_matrix[2][3] == 0 && 331 m_matrix[3][3] == 1; 332 } 333 334 Matrix4 m_matrix; 335 }; 336 337 } // namespace WebCore 338 339 #endif // TransformationMatrix_h 340