306a4ca5e94370501a00de1fc58fbb4e42320c5f
[WebKit-https.git] / WebCore / platform / graphics / transforms / TransformationMatrix.h
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 #if PLATFORM(CG)
30 #include <CoreGraphics/CGAffineTransform.h>
31 #elif PLATFORM(CAIRO)
32 #include <cairo.h>
33 #elif PLATFORM(QT)
34 #include <QMatrix>
35 #elif PLATFORM(SKIA)
36 #include <SkMatrix.h>
37 #elif PLATFORM(WX) && USE(WXGC)
38 #include <wx/graphics.h>
39 #endif
40
41 #include <string.h> //for memcpy
42
43 namespace WebCore {
44
45 class IntPoint;
46 class IntRect;
47 class FloatPoint;
48 class FloatPoint3D;
49 class FloatRect;
50 class FloatQuad;
51
52 class TransformationMatrix {
53 public:
54     typedef double Matrix4[4][4];
55
56     TransformationMatrix() { makeIdentity(); }
57     TransformationMatrix(const TransformationMatrix& t) { *this = t; }
58     TransformationMatrix(double a, double b, double c, double d, double e, double f) { setMatrix(a, b, c, d, e, f); }
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
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     
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
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
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
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.
117     IntPoint mapPoint(const IntPoint&) const;
118
119     // If the matrix has 3D components, the z component of the result is
120     // dropped, effectively projecting the rect into the z=0 plane
121     FloatRect mapRect(const FloatRect&) const;
122
123     // Rounds the resulting mapped rectangle out. This is helpful for bounding
124     // box computations but may not be what is wanted in other contexts.
125     IntRect mapRect(const IntRect&) const;
126
127     // If the matrix has 3D components, the z component of the result is
128     // dropped, effectively projecting the quad into the z=0 plane
129     FloatQuad mapQuad(const FloatQuad&) const;
130
131     // Map a point on the z=0 plane into a point on
132     // the plane with with the transform applied, by extending
133     // a ray perpendicular to the source plane and computing
134     // the local x,y position of the point where that ray intersects
135     // with the destination plane.
136     FloatPoint projectPoint(const FloatPoint&) const;
137
138     double m11() const { return m_matrix[0][0]; }
139     void setM11(double f) { m_matrix[0][0] = f; }
140     double m12() const { return m_matrix[0][1]; }
141     void setM12(double f) { m_matrix[0][1] = f; }
142     double m13() const { return m_matrix[0][2]; }
143     void setM13(double f) { m_matrix[0][2] = f; }
144     double m14() const { return m_matrix[0][3]; }
145     void setM14(double f) { m_matrix[0][3] = f; }
146     double m21() const { return m_matrix[1][0]; }
147     void setM21(double f) { m_matrix[1][0] = f; }
148     double m22() const { return m_matrix[1][1]; }
149     void setM22(double f) { m_matrix[1][1] = f; }
150     double m23() const { return m_matrix[1][2]; }
151     void setM23(double f) { m_matrix[1][2] = f; }
152     double m24() const { return m_matrix[1][3]; }
153     void setM24(double f) { m_matrix[1][3] = f; }
154     double m31() const { return m_matrix[2][0]; }
155     void setM31(double f) { m_matrix[2][0] = f; }
156     double m32() const { return m_matrix[2][1]; }
157     void setM32(double f) { m_matrix[2][1] = f; }
158     double m33() const { return m_matrix[2][2]; }
159     void setM33(double f) { m_matrix[2][2] = f; }
160     double m34() const { return m_matrix[2][3]; }
161     void setM34(double f) { m_matrix[2][3] = f; }
162     double m41() const { return m_matrix[3][0]; }
163     void setM41(double f) { m_matrix[3][0] = f; }
164     double m42() const { return m_matrix[3][1]; }
165     void setM42(double f) { m_matrix[3][1] = f; }
166     double m43() const { return m_matrix[3][2]; }
167     void setM43(double f) { m_matrix[3][2] = f; }
168     double m44() const { return m_matrix[3][3]; }
169     void setM44(double f) { m_matrix[3][3] = f; }
170     
171     double a() const { return m_matrix[0][0]; }
172     void setA(double a) { m_matrix[0][0] = a; }
173
174     double b() const { return m_matrix[0][1]; }
175     void setB(double b) { m_matrix[0][1] = b; }
176
177     double c() const { return m_matrix[1][0]; }
178     void setC(double c) { m_matrix[1][0] = c; }
179
180     double d() const { return m_matrix[1][1]; }
181     void setD(double d) { m_matrix[1][1] = d; }
182
183     double e() const { return m_matrix[3][0]; }
184     void setE(double e) { m_matrix[3][0] = e; }
185
186     double f() const { return m_matrix[3][1]; }
187     void setF(double f) { m_matrix[3][1] = f; }
188
189     // this = this * mat
190     TransformationMatrix& multiply(const TransformationMatrix& t) { return *this *= t; }
191
192     // this = mat * this
193     TransformationMatrix& multLeft(const TransformationMatrix& mat);
194     
195     TransformationMatrix& scale(double);
196     TransformationMatrix& scaleNonUniform(double sx, double sy);
197     TransformationMatrix& scale3d(double sx, double sy, double sz);
198     
199     TransformationMatrix& rotate(double d) { return rotate3d(0, 0, d); }
200     TransformationMatrix& rotateFromVector(double x, double y);
201     TransformationMatrix& rotate3d(double rx, double ry, double rz);
202     
203     // The vector (x,y,z) is normalized if it's not already. A vector of
204     // (0,0,0) uses a vector of (0,0,1).
205     TransformationMatrix& rotate3d(double x, double y, double z, double angle);
206     
207     TransformationMatrix& translate(double tx, double ty);
208     TransformationMatrix& translate3d(double tx, double ty, double tz);
209
210     // translation added with a post-multiply
211     TransformationMatrix& translateRight3d(double tx, double ty, double tz);
212     
213     TransformationMatrix& flipX();
214     TransformationMatrix& flipY();
215     TransformationMatrix& skew(double angleX, double angleY);
216     TransformationMatrix& skewX(double angle) { return skew(angle, 0); }
217     TransformationMatrix& skewY(double angle) { return skew(0, angle); }
218
219     TransformationMatrix& applyPerspective(double p);
220     bool hasPerspective() const { return m_matrix[2][3] != 0.0f; }
221
222     bool isInvertible() const;
223
224     // This method returns the identity matrix if it is not invertible.
225     // Use isInvertible() before calling this if you need to know.
226     TransformationMatrix inverse() const;
227
228     // decompose the matrix into its component parts
229     typedef struct {
230         double scaleX, scaleY, scaleZ;
231         double skewXY, skewXZ, skewYZ;
232         double quaternionX, quaternionY, quaternionZ, quaternionW;
233         double translateX, translateY, translateZ;
234         double perspectiveX, perspectiveY, perspectiveZ, perspectiveW;
235     } DecomposedType;
236     
237     bool decompose(DecomposedType& decomp) const;
238     void recompose(const DecomposedType& decomp);
239     
240     void blend(const TransformationMatrix& from, double progress);
241
242     bool isAffine() const
243     {
244         return (m13() == 0 && m14() == 0 && m23() == 0 && m24() == 0 && 
245                 m31() == 0 && m32() == 0 && m33() == 1 && m34() == 0 && m43() == 0 && m44() == 1);
246     }
247
248     bool operator==(const TransformationMatrix& m2) const
249     {
250         return (m_matrix[0][0] == m2.m_matrix[0][0] &&
251                 m_matrix[0][1] == m2.m_matrix[0][1] &&
252                 m_matrix[0][2] == m2.m_matrix[0][2] &&
253                 m_matrix[0][3] == m2.m_matrix[0][3] &&
254                 m_matrix[1][0] == m2.m_matrix[1][0] &&
255                 m_matrix[1][1] == m2.m_matrix[1][1] &&
256                 m_matrix[1][2] == m2.m_matrix[1][2] &&
257                 m_matrix[1][3] == m2.m_matrix[1][3] &&
258                 m_matrix[2][0] == m2.m_matrix[2][0] &&
259                 m_matrix[2][1] == m2.m_matrix[2][1] &&
260                 m_matrix[2][2] == m2.m_matrix[2][2] &&
261                 m_matrix[2][3] == m2.m_matrix[2][3] &&
262                 m_matrix[3][0] == m2.m_matrix[3][0] &&
263                 m_matrix[3][1] == m2.m_matrix[3][1] &&
264                 m_matrix[3][2] == m2.m_matrix[3][2] &&
265                 m_matrix[3][3] == m2.m_matrix[3][3]);
266     }
267
268     bool operator!=(const TransformationMatrix& other) const { return !(*this == other); }
269     
270     // *this = *this * t (i.e., a multRight)
271     TransformationMatrix& operator*=(const TransformationMatrix& t)
272     {
273         *this = *this * t;
274         return *this;
275     }
276     
277     // result = *this * t (i.e., a multRight)
278     TransformationMatrix operator*(const TransformationMatrix& t)
279     {
280         TransformationMatrix result = t;
281         result.multLeft(*this);
282         return result;
283     }
284
285 #if PLATFORM(CG)
286     operator CGAffineTransform() const;
287 #elif PLATFORM(CAIRO)
288     operator cairo_matrix_t() const;
289 #elif PLATFORM(QT)
290     operator QMatrix() const;
291 #elif PLATFORM(SKIA)
292     operator SkMatrix() const;
293 #elif PLATFORM(WX) && USE(WXGC)
294     operator wxGraphicsMatrix() const;
295 #endif
296
297 private:
298     // multiply passed 2D point by matrix (assume z=0)
299     void multVecMatrix(double x, double y, double& dstX, double& dstY) const;
300     
301     // multiply passed 3D point by matrix
302     void multVecMatrix(double x, double y, double z, double& dstX, double& dstY, double& dstZ) const;
303     
304     void setMatrix(const Matrix4 m)
305     {
306         if (m && m != m_matrix)
307             memcpy(m_matrix, m, sizeof(Matrix4));
308     }
309     
310     Matrix4 m_matrix;
311 };
312
313 } // namespace WebCore
314
315 #endif // TransformationMatrix_h