1/*
2 * Copyright (C) 2005-2016 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#pragma once
27
28#include "FloatPoint.h"
29#include "FloatPoint3D.h"
30#include "IntPoint.h"
31#include <array>
32#include <string.h> //for memcpy
33#include <wtf/FastMalloc.h>
34#include <wtf/Forward.h>
35
36#if USE(CA)
37typedef struct CATransform3D CATransform3D;
38#endif
39#if USE(CG)
40typedef struct CGAffineTransform CGAffineTransform;
41#endif
42
43#if PLATFORM(WIN) || (PLATFORM(GTK) && OS(WINDOWS))
44#if COMPILER(MINGW) && !COMPILER(MINGW64)
45typedef struct _XFORM XFORM;
46#else
47typedef struct tagXFORM XFORM;
48#endif
49#endif
50
51#if PLATFORM(WIN)
52struct D2D_MATRIX_3X2_F;
53typedef D2D_MATRIX_3X2_F D2D1_MATRIX_3X2_F;
54#endif
55
56namespace WTF {
57class TextStream;
58}
59
60namespace WebCore {
61
62class AffineTransform;
63class IntRect;
64class LayoutRect;
65class FloatRect;
66class FloatQuad;
67
68#if CPU(X86_64)
69#define TRANSFORMATION_MATRIX_USE_X86_64_SSE2
70#endif
71
72class TransformationMatrix {
73 WTF_MAKE_FAST_ALLOCATED;
74public:
75
76#if (PLATFORM(IOS_FAMILY) && CPU(ARM_THUMB2)) || defined(TRANSFORMATION_MATRIX_USE_X86_64_SSE2)
77#if COMPILER(MSVC)
78 __declspec(align(16)) typedef double Matrix4[4][4];
79#else
80 typedef double Matrix4[4][4] __attribute__((aligned (16)));
81#endif
82#else
83 typedef double Matrix4[4][4];
84#endif
85
86 constexpr TransformationMatrix()
87 : m_matrix {
88 { 1, 0, 0, 0 },
89 { 0, 1, 0, 0 },
90 { 0, 0, 1, 0 },
91 { 0, 0, 0, 1 },
92 }
93 {
94 }
95
96 constexpr TransformationMatrix(double a, double b, double c, double d, double e, double f)
97 : m_matrix {
98 { a, b, 0, 0 },
99 { c, d, 0, 0 },
100 { 0, 0, 1, 0 },
101 { e, f, 0, 1 },
102 }
103 {
104 }
105
106 constexpr TransformationMatrix(
107 double m11, double m12, double m13, double m14,
108 double m21, double m22, double m23, double m24,
109 double m31, double m32, double m33, double m34,
110 double m41, double m42, double m43, double m44)
111 : m_matrix {
112 { m11, m12, m13, m14 },
113 { m21, m22, m23, m24 },
114 { m31, m32, m33, m34 },
115 { m41, m42, m43, m44 },
116 }
117 {
118 }
119
120 WEBCORE_EXPORT TransformationMatrix(const AffineTransform&);
121
122 static const TransformationMatrix identity;
123
124 void setMatrix(double a, double b, double c, double d, double e, double f)
125 {
126 m_matrix[0][0] = a; m_matrix[0][1] = b; m_matrix[0][2] = 0; m_matrix[0][3] = 0;
127 m_matrix[1][0] = c; m_matrix[1][1] = d; m_matrix[1][2] = 0; m_matrix[1][3] = 0;
128 m_matrix[2][0] = 0; m_matrix[2][1] = 0; m_matrix[2][2] = 1; m_matrix[2][3] = 0;
129 m_matrix[3][0] = e; m_matrix[3][1] = f; m_matrix[3][2] = 0; m_matrix[3][3] = 1;
130 }
131
132 void setMatrix(double m11, double m12, double m13, double m14,
133 double m21, double m22, double m23, double m24,
134 double m31, double m32, double m33, double m34,
135 double m41, double m42, double m43, double m44)
136 {
137 m_matrix[0][0] = m11; m_matrix[0][1] = m12; m_matrix[0][2] = m13; m_matrix[0][3] = m14;
138 m_matrix[1][0] = m21; m_matrix[1][1] = m22; m_matrix[1][2] = m23; m_matrix[1][3] = m24;
139 m_matrix[2][0] = m31; m_matrix[2][1] = m32; m_matrix[2][2] = m33; m_matrix[2][3] = m34;
140 m_matrix[3][0] = m41; m_matrix[3][1] = m42; m_matrix[3][2] = m43; m_matrix[3][3] = m44;
141 }
142
143 TransformationMatrix& makeIdentity()
144 {
145 setMatrix(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
146 return *this;
147 }
148
149 bool isIdentity() const
150 {
151 return m_matrix[0][0] == 1 && m_matrix[0][1] == 0 && m_matrix[0][2] == 0 && m_matrix[0][3] == 0 &&
152 m_matrix[1][0] == 0 && m_matrix[1][1] == 1 && m_matrix[1][2] == 0 && m_matrix[1][3] == 0 &&
153 m_matrix[2][0] == 0 && m_matrix[2][1] == 0 && m_matrix[2][2] == 1 && m_matrix[2][3] == 0 &&
154 m_matrix[3][0] == 0 && m_matrix[3][1] == 0 && m_matrix[3][2] == 0 && m_matrix[3][3] == 1;
155 }
156
157 // This form preserves the double math from input to output.
158 void map(double x, double y, double& x2, double& y2) const { multVecMatrix(x, y, x2, y2); }
159 void map4ComponentPoint(double& x, double& y, double& z, double& w) const;
160
161 // Maps a 3D point through the transform, returning a 3D point.
162 FloatPoint3D mapPoint(const FloatPoint3D&) const;
163
164 // Maps a 2D point through the transform, returning a 2D point.
165 // Note that this ignores the z component, effectively projecting the point into the z=0 plane.
166 WEBCORE_EXPORT FloatPoint mapPoint(const FloatPoint&) const;
167
168 // Like the version above, except that it rounds the mapped point to the nearest integer value.
169 IntPoint mapPoint(const IntPoint& p) const
170 {
171 return roundedIntPoint(mapPoint(FloatPoint(p)));
172 }
173
174 // If the matrix has 3D components, the z component of the result is
175 // dropped, effectively projecting the rect into the z=0 plane.
176 WEBCORE_EXPORT FloatRect mapRect(const FloatRect&) const;
177
178 // Rounds the resulting mapped rectangle out. This is helpful for bounding
179 // box computations but may not be what is wanted in other contexts.
180 WEBCORE_EXPORT IntRect mapRect(const IntRect&) const;
181 LayoutRect mapRect(const LayoutRect&) const;
182
183 // If the matrix has 3D components, the z component of the result is
184 // dropped, effectively projecting the quad into the z=0 plane.
185 WEBCORE_EXPORT FloatQuad mapQuad(const FloatQuad&) const;
186
187 // Maps a point on the z=0 plane into a point on the plane with with the transform applied, by
188 // extending a ray perpendicular to the source plane and computing the local x,y position of
189 // the point where that ray intersects with the destination plane.
190 FloatPoint projectPoint(const FloatPoint&, bool* clamped = 0) const;
191 // Projects the four corners of the quad.
192 FloatQuad projectQuad(const FloatQuad&, bool* clamped = 0) const;
193 // Projects the four corners of the quad and takes a bounding box,
194 // while sanitizing values created when the w component is negative.
195 LayoutRect clampedBoundsOfProjectedQuad(const FloatQuad&) const;
196
197 double m11() const { return m_matrix[0][0]; }
198 void setM11(double f) { m_matrix[0][0] = f; }
199 double m12() const { return m_matrix[0][1]; }
200 void setM12(double f) { m_matrix[0][1] = f; }
201 double m13() const { return m_matrix[0][2]; }
202 void setM13(double f) { m_matrix[0][2] = f; }
203 double m14() const { return m_matrix[0][3]; }
204 void setM14(double f) { m_matrix[0][3] = f; }
205 double m21() const { return m_matrix[1][0]; }
206 void setM21(double f) { m_matrix[1][0] = f; }
207 double m22() const { return m_matrix[1][1]; }
208 void setM22(double f) { m_matrix[1][1] = f; }
209 double m23() const { return m_matrix[1][2]; }
210 void setM23(double f) { m_matrix[1][2] = f; }
211 double m24() const { return m_matrix[1][3]; }
212 void setM24(double f) { m_matrix[1][3] = f; }
213 double m31() const { return m_matrix[2][0]; }
214 void setM31(double f) { m_matrix[2][0] = f; }
215 double m32() const { return m_matrix[2][1]; }
216 void setM32(double f) { m_matrix[2][1] = f; }
217 double m33() const { return m_matrix[2][2]; }
218 void setM33(double f) { m_matrix[2][2] = f; }
219 double m34() const { return m_matrix[2][3]; }
220 void setM34(double f) { m_matrix[2][3] = f; }
221 double m41() const { return m_matrix[3][0]; }
222 void setM41(double f) { m_matrix[3][0] = f; }
223 double m42() const { return m_matrix[3][1]; }
224 void setM42(double f) { m_matrix[3][1] = f; }
225 double m43() const { return m_matrix[3][2]; }
226 void setM43(double f) { m_matrix[3][2] = f; }
227 double m44() const { return m_matrix[3][3]; }
228 void setM44(double f) { m_matrix[3][3] = f; }
229
230 double a() const { return m_matrix[0][0]; }
231 void setA(double a) { m_matrix[0][0] = a; }
232
233 double b() const { return m_matrix[0][1]; }
234 void setB(double b) { m_matrix[0][1] = b; }
235
236 double c() const { return m_matrix[1][0]; }
237 void setC(double c) { m_matrix[1][0] = c; }
238
239 double d() const { return m_matrix[1][1]; }
240 void setD(double d) { m_matrix[1][1] = d; }
241
242 double e() const { return m_matrix[3][0]; }
243 void setE(double e) { m_matrix[3][0] = e; }
244
245 double f() const { return m_matrix[3][1]; }
246 void setF(double f) { m_matrix[3][1] = f; }
247
248 // this = mat * this.
249 WEBCORE_EXPORT TransformationMatrix& multiply(const TransformationMatrix&);
250
251 WEBCORE_EXPORT TransformationMatrix& scale(double);
252 WEBCORE_EXPORT TransformationMatrix& scaleNonUniform(double sx, double sy);
253 TransformationMatrix& scale3d(double sx, double sy, double sz);
254
255 // Angle is in degrees.
256 TransformationMatrix& rotate(double d) { return rotate3d(0, 0, d); }
257 TransformationMatrix& rotateFromVector(double x, double y);
258 WEBCORE_EXPORT TransformationMatrix& rotate3d(double rx, double ry, double rz);
259
260 // 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).
261 TransformationMatrix& rotate3d(double x, double y, double z, double angle);
262
263 WEBCORE_EXPORT TransformationMatrix& translate(double tx, double ty);
264 TransformationMatrix& translate3d(double tx, double ty, double tz);
265
266 // translation added with a post-multiply
267 TransformationMatrix& translateRight(double tx, double ty);
268 TransformationMatrix& translateRight3d(double tx, double ty, double tz);
269
270 WEBCORE_EXPORT TransformationMatrix& flipX();
271 WEBCORE_EXPORT TransformationMatrix& flipY();
272 WEBCORE_EXPORT TransformationMatrix& skew(double angleX, double angleY);
273 TransformationMatrix& skewX(double angle) { return skew(angle, 0); }
274 TransformationMatrix& skewY(double angle) { return skew(0, angle); }
275
276 TransformationMatrix& applyPerspective(double p);
277 bool hasPerspective() const { return m_matrix[2][3] != 0.0f; }
278
279 // Returns a transformation that maps a rect to a rect.
280 WEBCORE_EXPORT static TransformationMatrix rectToRect(const FloatRect&, const FloatRect&);
281
282 bool isInvertible() const; // If you call this this, you're probably doing it wrong.
283 WEBCORE_EXPORT Optional<TransformationMatrix> inverse() const;
284
285 // Decompose the matrix into its component parts.
286 struct Decomposed2Type {
287 double scaleX, scaleY;
288 double translateX, translateY;
289 double angle;
290 double m11, m12, m21, m22;
291
292 bool operator==(const Decomposed2Type& other) const
293 {
294 return scaleX == other.scaleX && scaleY == other.scaleY
295 && translateX == other.translateX && translateY == other.translateY
296 && angle == other.angle
297 && m11 == other.m11 && m12 == other.m12 && m21 == other.m21 && m22 == other.m22;
298 }
299 };
300
301 struct Decomposed4Type {
302 double scaleX, scaleY, scaleZ;
303 double skewXY, skewXZ, skewYZ;
304 double quaternionX, quaternionY, quaternionZ, quaternionW;
305 double translateX, translateY, translateZ;
306 double perspectiveX, perspectiveY, perspectiveZ, perspectiveW;
307
308 bool operator==(const Decomposed4Type& other) const
309 {
310 return scaleX == other.scaleX && scaleY == other.scaleY && scaleZ == other.scaleZ
311 && skewXY == other.skewXY && skewXZ == other.skewXZ && skewYZ == other.skewYZ
312 && quaternionX == other.quaternionX && quaternionY == other.quaternionY && quaternionZ == other.quaternionZ && quaternionW == other.quaternionW
313 && translateX == other.translateX && translateY == other.translateY && translateZ == other.translateZ
314 && perspectiveX == other.perspectiveX && perspectiveY == other.perspectiveY && perspectiveZ == other.perspectiveZ && perspectiveW == other.perspectiveW;
315 }
316 };
317
318 bool decompose2(Decomposed2Type&) const;
319 void recompose2(const Decomposed2Type&);
320
321 bool decompose4(Decomposed4Type&) const;
322 void recompose4(const Decomposed4Type&);
323
324 WEBCORE_EXPORT void blend(const TransformationMatrix& from, double progress);
325 WEBCORE_EXPORT void blend2(const TransformationMatrix& from, double progress);
326 WEBCORE_EXPORT void blend4(const TransformationMatrix& from, double progress);
327
328 bool isAffine() const
329 {
330 return (m13() == 0 && m14() == 0 && m23() == 0 && m24() == 0 &&
331 m31() == 0 && m32() == 0 && m33() == 1 && m34() == 0 && m43() == 0 && m44() == 1);
332 }
333
334 // Throw away the non-affine parts of the matrix (lossy!).
335 WEBCORE_EXPORT void makeAffine();
336
337 WEBCORE_EXPORT AffineTransform toAffineTransform() const;
338
339 bool operator==(const TransformationMatrix& m2) const
340 {
341 return (m_matrix[0][0] == m2.m_matrix[0][0] &&
342 m_matrix[0][1] == m2.m_matrix[0][1] &&
343 m_matrix[0][2] == m2.m_matrix[0][2] &&
344 m_matrix[0][3] == m2.m_matrix[0][3] &&
345 m_matrix[1][0] == m2.m_matrix[1][0] &&
346 m_matrix[1][1] == m2.m_matrix[1][1] &&
347 m_matrix[1][2] == m2.m_matrix[1][2] &&
348 m_matrix[1][3] == m2.m_matrix[1][3] &&
349 m_matrix[2][0] == m2.m_matrix[2][0] &&
350 m_matrix[2][1] == m2.m_matrix[2][1] &&
351 m_matrix[2][2] == m2.m_matrix[2][2] &&
352 m_matrix[2][3] == m2.m_matrix[2][3] &&
353 m_matrix[3][0] == m2.m_matrix[3][0] &&
354 m_matrix[3][1] == m2.m_matrix[3][1] &&
355 m_matrix[3][2] == m2.m_matrix[3][2] &&
356 m_matrix[3][3] == m2.m_matrix[3][3]);
357 }
358
359 bool operator!=(const TransformationMatrix& other) const { return !(*this == other); }
360
361 // *this = *this * t
362 TransformationMatrix& operator*=(const TransformationMatrix& t)
363 {
364 return multiply(t);
365 }
366
367 // result = *this * t
368 TransformationMatrix operator*(const TransformationMatrix& t) const
369 {
370 TransformationMatrix result = *this;
371 result.multiply(t);
372 return result;
373 }
374
375#if USE(CA)
376 WEBCORE_EXPORT TransformationMatrix(const CATransform3D&);
377 WEBCORE_EXPORT operator CATransform3D() const;
378#endif
379#if USE(CG)
380 WEBCORE_EXPORT TransformationMatrix(const CGAffineTransform&);
381 WEBCORE_EXPORT operator CGAffineTransform() const;
382#endif
383
384#if PLATFORM(WIN) || (PLATFORM(GTK) && OS(WINDOWS))
385 operator XFORM() const;
386#endif
387
388#if PLATFORM(WIN)
389 TransformationMatrix(const D2D1_MATRIX_3X2_F&);
390 operator D2D1_MATRIX_3X2_F() const;
391#endif
392
393 bool isIdentityOrTranslation() const
394 {
395 return m_matrix[0][0] == 1 && m_matrix[0][1] == 0 && m_matrix[0][2] == 0 && m_matrix[0][3] == 0
396 && m_matrix[1][0] == 0 && m_matrix[1][1] == 1 && m_matrix[1][2] == 0 && m_matrix[1][3] == 0
397 && m_matrix[2][0] == 0 && m_matrix[2][1] == 0 && m_matrix[2][2] == 1 && m_matrix[2][3] == 0
398 && m_matrix[3][3] == 1;
399 }
400
401 bool isIntegerTranslation() const;
402
403 bool containsOnlyFiniteValues() const;
404
405 // Returns the matrix without 3D components.
406 TransformationMatrix to2dTransform() const;
407
408 using FloatMatrix4 = std::array<float, 16>;
409 FloatMatrix4 toColumnMajorFloatArray() const;
410
411 // A local-space layer is implicitly defined at the z = 0 plane, with its front side
412 // facing the positive z-axis (i.e. a camera looking along the negative z-axis sees
413 // the front side of the layer). This function checks if the transformed layer's back
414 // face would be visible to a camera looking along the negative z-axis in the target space.
415 bool isBackFaceVisible() const;
416
417private:
418 // multiply passed 2D point by matrix (assume z=0)
419 void multVecMatrix(double x, double y, double& dstX, double& dstY) const;
420 FloatPoint internalMapPoint(const FloatPoint& sourcePoint) const
421 {
422 double resultX;
423 double resultY;
424 multVecMatrix(sourcePoint.x(), sourcePoint.y(), resultX, resultY);
425 return FloatPoint(static_cast<float>(resultX), static_cast<float>(resultY));
426 }
427
428 void multVecMatrix(double x, double y, double z, double& dstX, double& dstY, double& dstZ) const;
429 FloatPoint3D internalMapPoint(const FloatPoint3D& sourcePoint) const
430 {
431 double resultX;
432 double resultY;
433 double resultZ;
434 multVecMatrix(sourcePoint.x(), sourcePoint.y(), sourcePoint.z(), resultX, resultY, resultZ);
435 return FloatPoint3D(static_cast<float>(resultX), static_cast<float>(resultY), static_cast<float>(resultZ));
436 }
437
438 Matrix4 m_matrix;
439};
440
441WEBCORE_EXPORT WTF::TextStream& operator<<(WTF::TextStream&, const TransformationMatrix&);
442
443} // namespace WebCore
444