[WTF] Import std::optional reference implementation as WTF::Optional
[WebKit-https.git] / Source / WebCore / platform / graphics / transforms / AffineTransform.cpp
1 /*
2  * Copyright (C) 2005, 2006 Apple Inc.  All rights reserved.
3  *               2010 Dirk Schulze <krit@webkit.org>
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
25  */
26
27 #include "config.h"
28 #include "AffineTransform.h"
29
30 #include "FloatConversion.h"
31 #include "FloatQuad.h"
32 #include "FloatRect.h"
33 #include "IntRect.h"
34 #include "TextStream.h"
35 #include "TransformationMatrix.h"
36
37 #include <wtf/MathExtras.h>
38
39 namespace WebCore {
40
41 #if COMPILER(MSVC)
42 AffineTransform::AffineTransform()
43 {
44     m_transform = { 1, 0, 0, 1, 0, 0 };
45 }
46
47 AffineTransform::AffineTransform(double a, double b, double c, double d, double e, double f)
48 {
49     m_transform = { a, b, c, d, e, f };
50 }
51 #else
52 AffineTransform::AffineTransform()
53     : m_transform { { 1, 0, 0, 1, 0, 0 } }
54 {
55 }
56
57 AffineTransform::AffineTransform(double a, double b, double c, double d, double e, double f)
58     : m_transform{ { a, b, c, d, e, f } }
59 {
60 }
61 #endif
62
63 void AffineTransform::makeIdentity()
64 {
65     setMatrix(1, 0, 0, 1, 0, 0);
66 }
67
68 void AffineTransform::setMatrix(double a, double b, double c, double d, double e, double f)
69 {
70     m_transform[0] = a;
71     m_transform[1] = b;
72     m_transform[2] = c;
73     m_transform[3] = d;
74     m_transform[4] = e;
75     m_transform[5] = f;
76 }
77
78 bool AffineTransform::isIdentity() const
79 {
80     return (m_transform[0] == 1 && m_transform[1] == 0
81          && m_transform[2] == 0 && m_transform[3] == 1
82          && m_transform[4] == 0 && m_transform[5] == 0);
83 }
84
85 double AffineTransform::xScale() const
86 {
87     return sqrt(m_transform[0] * m_transform[0] + m_transform[1] * m_transform[1]);
88 }
89
90 double AffineTransform::yScale() const
91 {
92     return sqrt(m_transform[2] * m_transform[2] + m_transform[3] * m_transform[3]);
93 }
94
95 static double det(const std::array<double, 6>& transform)
96 {
97     return transform[0] * transform[3] - transform[1] * transform[2];
98 }
99
100 bool AffineTransform::isInvertible() const
101 {
102     double determinant = det(m_transform);
103
104     return std::isfinite(determinant) && determinant != 0;
105 }
106
107 std::optional<AffineTransform> AffineTransform::inverse() const
108 {
109     double determinant = det(m_transform);
110     if (!std::isfinite(determinant) || determinant == 0)
111         return std::nullopt;
112
113     AffineTransform result;
114     if (isIdentityOrTranslation()) {
115         result.m_transform[4] = -m_transform[4];
116         result.m_transform[5] = -m_transform[5];
117         return result;
118     }
119
120     result.m_transform[0] = m_transform[3] / determinant;
121     result.m_transform[1] = -m_transform[1] / determinant;
122     result.m_transform[2] = -m_transform[2] / determinant;
123     result.m_transform[3] = m_transform[0] / determinant;
124     result.m_transform[4] = (m_transform[2] * m_transform[5]
125                            - m_transform[3] * m_transform[4]) / determinant;
126     result.m_transform[5] = (m_transform[1] * m_transform[4]
127                            - m_transform[0] * m_transform[5]) / determinant;
128
129     return result;
130 }
131
132
133 // Multiplies this AffineTransform by the provided AffineTransform - i.e.
134 // this = this * other;
135 AffineTransform& AffineTransform::multiply(const AffineTransform& other)
136 {
137     AffineTransform trans;
138     
139     trans.m_transform[0] = other.m_transform[0] * m_transform[0] + other.m_transform[1] * m_transform[2];
140     trans.m_transform[1] = other.m_transform[0] * m_transform[1] + other.m_transform[1] * m_transform[3];
141     trans.m_transform[2] = other.m_transform[2] * m_transform[0] + other.m_transform[3] * m_transform[2];
142     trans.m_transform[3] = other.m_transform[2] * m_transform[1] + other.m_transform[3] * m_transform[3];
143     trans.m_transform[4] = other.m_transform[4] * m_transform[0] + other.m_transform[5] * m_transform[2] + m_transform[4];
144     trans.m_transform[5] = other.m_transform[4] * m_transform[1] + other.m_transform[5] * m_transform[3] + m_transform[5];
145
146     *this = trans;
147     return *this;
148 }
149
150 AffineTransform& AffineTransform::rotate(double a)
151 {
152     // angle is in degree. Switch to radian
153     a = deg2rad(a);
154     double cosAngle = cos(a);
155     double sinAngle = sin(a);
156     AffineTransform rot(cosAngle, sinAngle, -sinAngle, cosAngle, 0, 0);
157
158     multiply(rot);
159     return *this;
160 }
161
162 AffineTransform& AffineTransform::scale(double s)
163 {
164     return scale(s, s);
165 }
166
167 AffineTransform& AffineTransform::scale(double sx, double sy)
168 {
169     m_transform[0] *= sx;
170     m_transform[1] *= sx;
171     m_transform[2] *= sy;
172     m_transform[3] *= sy;
173     return *this;
174 }
175
176 AffineTransform& AffineTransform::scaleNonUniform(double sx, double sy)
177 {
178     return scale(sx, sy);
179 }
180
181 AffineTransform& AffineTransform::scale(const FloatSize& s)
182 {
183     return scale(s.width(), s.height());
184 }
185
186 // *this = *this * translation
187 AffineTransform& AffineTransform::translate(double tx, double ty)
188 {
189     if (isIdentityOrTranslation()) {
190         m_transform[4] += tx;
191         m_transform[5] += ty;
192         return *this;
193     }
194         
195     m_transform[4] += tx * m_transform[0] + ty * m_transform[2];
196     m_transform[5] += tx * m_transform[1] + ty * m_transform[3];
197     return *this;
198 }
199
200 AffineTransform& AffineTransform::translate(const FloatPoint& t)
201 {
202     return translate(t.x(), t.y());
203 }
204
205 AffineTransform& AffineTransform::rotateFromVector(double x, double y)
206 {
207     return rotate(rad2deg(atan2(y, x)));
208 }
209
210 AffineTransform& AffineTransform::flipX()
211 {
212     return scale(-1, 1);
213 }
214
215 AffineTransform& AffineTransform::flipY()
216 {
217     return scale(1, -1);
218 }
219
220 AffineTransform& AffineTransform::shear(double sx, double sy)
221 {
222     double a = m_transform[0];
223     double b = m_transform[1];
224
225     m_transform[0] += sy * m_transform[2];
226     m_transform[1] += sy * m_transform[3];
227     m_transform[2] += sx * a;
228     m_transform[3] += sx * b;
229
230     return *this;
231 }
232
233 AffineTransform& AffineTransform::skew(double angleX, double angleY)
234 {
235     return shear(tan(deg2rad(angleX)), tan(deg2rad(angleY)));
236 }
237
238 AffineTransform& AffineTransform::skewX(double angle)
239 {
240     return shear(tan(deg2rad(angle)), 0);
241 }
242
243 AffineTransform& AffineTransform::skewY(double angle)
244 {
245     return shear(0, tan(deg2rad(angle)));
246 }
247
248 AffineTransform makeMapBetweenRects(const FloatRect& source, const FloatRect& dest)
249 {
250     AffineTransform transform;
251     transform.translate(dest.x() - source.x(), dest.y() - source.y());
252     transform.scale(dest.width() / source.width(), dest.height() / source.height());
253     return transform;
254 }
255
256 void AffineTransform::map(double x, double y, double& x2, double& y2) const
257 {
258     x2 = (m_transform[0] * x + m_transform[2] * y + m_transform[4]);
259     y2 = (m_transform[1] * x + m_transform[3] * y + m_transform[5]);
260 }
261
262 IntPoint AffineTransform::mapPoint(const IntPoint& point) const
263 {
264     double x2, y2;
265     map(point.x(), point.y(), x2, y2);
266     
267     // Round the point.
268     return IntPoint(lround(x2), lround(y2));
269 }
270
271 FloatPoint AffineTransform::mapPoint(const FloatPoint& point) const
272 {
273     double x2, y2;
274     map(point.x(), point.y(), x2, y2);
275
276     return FloatPoint(narrowPrecisionToFloat(x2), narrowPrecisionToFloat(y2));
277 }
278
279 IntSize AffineTransform::mapSize(const IntSize& size) const
280 {
281     double width2 = size.width() * xScale();
282     double height2 = size.height() * yScale();
283
284     return IntSize(lround(width2), lround(height2));
285 }
286
287 FloatSize AffineTransform::mapSize(const FloatSize& size) const
288 {
289     double width2 = size.width() * xScale();
290     double height2 = size.height() * yScale();
291
292     return FloatSize(narrowPrecisionToFloat(width2), narrowPrecisionToFloat(height2));
293 }
294
295 IntRect AffineTransform::mapRect(const IntRect &rect) const
296 {
297     return enclosingIntRect(mapRect(FloatRect(rect)));
298 }
299
300 FloatRect AffineTransform::mapRect(const FloatRect& rect) const
301 {
302     if (isIdentityOrTranslation()) {
303         FloatRect mappedRect(rect);
304         mappedRect.move(narrowPrecisionToFloat(m_transform[4]), narrowPrecisionToFloat(m_transform[5]));
305         return mappedRect;
306     }
307
308     FloatQuad result;
309     result.setP1(mapPoint(rect.location()));
310     result.setP2(mapPoint(FloatPoint(rect.maxX(), rect.y())));
311     result.setP3(mapPoint(FloatPoint(rect.maxX(), rect.maxY())));
312     result.setP4(mapPoint(FloatPoint(rect.x(), rect.maxY())));
313     return result.boundingBox();
314 }
315
316 FloatQuad AffineTransform::mapQuad(const FloatQuad& q) const
317 {
318     if (isIdentityOrTranslation()) {
319         FloatQuad mappedQuad(q);
320         mappedQuad.move(narrowPrecisionToFloat(m_transform[4]), narrowPrecisionToFloat(m_transform[5]));
321         return mappedQuad;
322     }
323
324     FloatQuad result;
325     result.setP1(mapPoint(q.p1()));
326     result.setP2(mapPoint(q.p2()));
327     result.setP3(mapPoint(q.p3()));
328     result.setP4(mapPoint(q.p4()));
329     return result;
330 }
331
332 void AffineTransform::blend(const AffineTransform& from, double progress)
333 {
334     DecomposedType srA, srB;
335
336     from.decompose(srA);
337     this->decompose(srB);
338
339     // If x-axis of one is flipped, and y-axis of the other, convert to an unflipped rotation.
340     if ((srA.scaleX < 0 && srB.scaleY < 0) || (srA.scaleY < 0 &&  srB.scaleX < 0)) {
341         srA.scaleX = -srA.scaleX;
342         srA.scaleY = -srA.scaleY;
343         srA.angle += srA.angle < 0 ? piDouble : -piDouble;
344     }
345
346     // Don't rotate the long way around.
347     srA.angle = fmod(srA.angle, 2 * piDouble);
348     srB.angle = fmod(srB.angle, 2 * piDouble);
349
350     if (fabs(srA.angle - srB.angle) > piDouble) {
351         if (srA.angle > srB.angle)
352             srA.angle -= piDouble * 2;
353         else
354             srB.angle -= piDouble * 2;
355     }
356     
357     srA.scaleX += progress * (srB.scaleX - srA.scaleX);
358     srA.scaleY += progress * (srB.scaleY - srA.scaleY);
359     srA.angle += progress * (srB.angle - srA.angle);
360     srA.remainderA += progress * (srB.remainderA - srA.remainderA);
361     srA.remainderB += progress * (srB.remainderB - srA.remainderB);
362     srA.remainderC += progress * (srB.remainderC - srA.remainderC);
363     srA.remainderD += progress * (srB.remainderD - srA.remainderD);
364     srA.translateX += progress * (srB.translateX - srA.translateX);
365     srA.translateY += progress * (srB.translateY - srA.translateY);
366
367     this->recompose(srA);
368 }
369
370 TransformationMatrix AffineTransform::toTransformationMatrix() const
371 {
372     return TransformationMatrix(m_transform[0], m_transform[1], m_transform[2],
373                                 m_transform[3], m_transform[4], m_transform[5]);
374 }
375
376 bool AffineTransform::decompose(DecomposedType& decomp) const
377 {
378     AffineTransform m(*this);
379     
380     // Compute scaling factors
381     double sx = xScale();
382     double sy = yScale();
383     
384     // Compute cross product of transformed unit vectors. If negative,
385     // one axis was flipped.
386     if (m.a() * m.d() - m.c() * m.b() < 0) {
387         // Flip axis with minimum unit vector dot product
388         if (m.a() < m.d())
389             sx = -sx;
390         else
391             sy = -sy;
392     }
393     
394     // Remove scale from matrix
395     m.scale(1 / sx, 1 / sy);
396     
397     // Compute rotation
398     double angle = atan2(m.b(), m.a());
399     
400     // Remove rotation from matrix
401     m.rotate(rad2deg(-angle));
402     
403     // Return results    
404     decomp.scaleX = sx;
405     decomp.scaleY = sy;
406     decomp.angle = angle;
407     decomp.remainderA = m.a();
408     decomp.remainderB = m.b();
409     decomp.remainderC = m.c();
410     decomp.remainderD = m.d();
411     decomp.translateX = m.e();
412     decomp.translateY = m.f();
413     
414     return true;
415 }
416
417 void AffineTransform::recompose(const DecomposedType& decomp)
418 {
419     this->setA(decomp.remainderA);
420     this->setB(decomp.remainderB);
421     this->setC(decomp.remainderC);
422     this->setD(decomp.remainderD);
423     this->setE(decomp.translateX);
424     this->setF(decomp.translateY);
425     this->rotate(rad2deg(decomp.angle));
426     this->scale(decomp.scaleX, decomp.scaleY);
427 }
428
429 TextStream& operator<<(TextStream& ts, const AffineTransform& transform)
430 {
431     if (transform.isIdentity())
432         ts << "identity";
433     else
434         ts << "{m=(("
435         << transform.a() << "," << transform.b()
436         << ")("
437         << transform.c() << "," << transform.d()
438         << ")) t=("
439         << transform.e() << "," << transform.f()
440         << ")}";
441
442     return ts;
443 }
444
445 }