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