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) |
37 | typedef struct CATransform3D CATransform3D; |
38 | #endif |
39 | #if USE(CG) |
40 | typedef struct CGAffineTransform CGAffineTransform; |
41 | #endif |
42 | |
43 | #if PLATFORM(WIN) || (PLATFORM(GTK) && OS(WINDOWS)) |
44 | #if COMPILER(MINGW) && !COMPILER(MINGW64) |
45 | typedef struct _XFORM XFORM; |
46 | #else |
47 | typedef struct tagXFORM XFORM; |
48 | #endif |
49 | #endif |
50 | |
51 | #if PLATFORM(WIN) |
52 | struct D2D_MATRIX_3X2_F; |
53 | typedef D2D_MATRIX_3X2_F D2D1_MATRIX_3X2_F; |
54 | #endif |
55 | |
56 | namespace WTF { |
57 | class TextStream; |
58 | } |
59 | |
60 | namespace WebCore { |
61 | |
62 | class AffineTransform; |
63 | class IntRect; |
64 | class LayoutRect; |
65 | class FloatRect; |
66 | class FloatQuad; |
67 | |
68 | #if CPU(X86_64) |
69 | #define TRANSFORMATION_MATRIX_USE_X86_64_SSE2 |
70 | #endif |
71 | |
72 | class TransformationMatrix { |
73 | WTF_MAKE_FAST_ALLOCATED; |
74 | public: |
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 | |
417 | private: |
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 | |
441 | WEBCORE_EXPORT WTF::TextStream& operator<<(WTF::TextStream&, const TransformationMatrix&); |
442 | |
443 | } // namespace WebCore |
444 | |