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 "Region.h"
35#include "TransformationMatrix.h"
36#include <wtf/MathExtras.h>
37#include <wtf/Optional.h>
38#include <wtf/text/TextStream.h>
39
40namespace WebCore {
41
42#if COMPILER(MSVC)
43AffineTransform::AffineTransform()
44{
45 m_transform = { 1, 0, 0, 1, 0, 0 };
46}
47
48AffineTransform::AffineTransform(double a, double b, double c, double d, double e, double f)
49{
50 m_transform = { a, b, c, d, e, f };
51}
52#else
53AffineTransform::AffineTransform()
54 : m_transform { { 1, 0, 0, 1, 0, 0 } }
55{
56}
57
58AffineTransform::AffineTransform(double a, double b, double c, double d, double e, double f)
59 : m_transform{ { a, b, c, d, e, f } }
60{
61}
62#endif
63
64void AffineTransform::makeIdentity()
65{
66 setMatrix(1, 0, 0, 1, 0, 0);
67}
68
69void AffineTransform::setMatrix(double a, double b, double c, double d, double e, double f)
70{
71 m_transform[0] = a;
72 m_transform[1] = b;
73 m_transform[2] = c;
74 m_transform[3] = d;
75 m_transform[4] = e;
76 m_transform[5] = f;
77}
78
79bool AffineTransform::isIdentity() const
80{
81 return (m_transform[0] == 1 && m_transform[1] == 0
82 && m_transform[2] == 0 && m_transform[3] == 1
83 && m_transform[4] == 0 && m_transform[5] == 0);
84}
85
86double AffineTransform::xScale() const
87{
88 return sqrt(m_transform[0] * m_transform[0] + m_transform[1] * m_transform[1]);
89}
90
91double AffineTransform::yScale() const
92{
93 return sqrt(m_transform[2] * m_transform[2] + m_transform[3] * m_transform[3]);
94}
95
96static double det(const std::array<double, 6>& transform)
97{
98 return transform[0] * transform[3] - transform[1] * transform[2];
99}
100
101bool AffineTransform::isInvertible() const
102{
103 double determinant = det(m_transform);
104
105 return std::isfinite(determinant) && determinant != 0;
106}
107
108Optional<AffineTransform> AffineTransform::inverse() const
109{
110 double determinant = det(m_transform);
111 if (!std::isfinite(determinant) || determinant == 0)
112 return WTF::nullopt;
113
114 AffineTransform result;
115 if (isIdentityOrTranslation()) {
116 result.m_transform[4] = -m_transform[4];
117 result.m_transform[5] = -m_transform[5];
118 return result;
119 }
120
121 result.m_transform[0] = m_transform[3] / determinant;
122 result.m_transform[1] = -m_transform[1] / determinant;
123 result.m_transform[2] = -m_transform[2] / determinant;
124 result.m_transform[3] = m_transform[0] / determinant;
125 result.m_transform[4] = (m_transform[2] * m_transform[5]
126 - m_transform[3] * m_transform[4]) / determinant;
127 result.m_transform[5] = (m_transform[1] * m_transform[4]
128 - m_transform[0] * m_transform[5]) / determinant;
129
130 return result;
131}
132
133
134// Multiplies this AffineTransform by the provided AffineTransform - i.e.
135// this = this * other;
136AffineTransform& AffineTransform::multiply(const AffineTransform& other)
137{
138 AffineTransform trans;
139
140 trans.m_transform[0] = other.m_transform[0] * m_transform[0] + other.m_transform[1] * m_transform[2];
141 trans.m_transform[1] = other.m_transform[0] * m_transform[1] + other.m_transform[1] * m_transform[3];
142 trans.m_transform[2] = other.m_transform[2] * m_transform[0] + other.m_transform[3] * m_transform[2];
143 trans.m_transform[3] = other.m_transform[2] * m_transform[1] + other.m_transform[3] * m_transform[3];
144 trans.m_transform[4] = other.m_transform[4] * m_transform[0] + other.m_transform[5] * m_transform[2] + m_transform[4];
145 trans.m_transform[5] = other.m_transform[4] * m_transform[1] + other.m_transform[5] * m_transform[3] + m_transform[5];
146
147 *this = trans;
148 return *this;
149}
150
151AffineTransform& AffineTransform::rotate(double a)
152{
153 // angle is in degree. Switch to radian
154 a = deg2rad(a);
155 double cosAngle = cos(a);
156 double sinAngle = sin(a);
157 AffineTransform rot(cosAngle, sinAngle, -sinAngle, cosAngle, 0, 0);
158
159 multiply(rot);
160 return *this;
161}
162
163AffineTransform& AffineTransform::scale(double s)
164{
165 return scale(s, s);
166}
167
168AffineTransform& AffineTransform::scale(double sx, double sy)
169{
170 m_transform[0] *= sx;
171 m_transform[1] *= sx;
172 m_transform[2] *= sy;
173 m_transform[3] *= sy;
174 return *this;
175}
176
177AffineTransform& AffineTransform::scaleNonUniform(double sx, double sy)
178{
179 return scale(sx, sy);
180}
181
182AffineTransform& AffineTransform::scale(const FloatSize& s)
183{
184 return scale(s.width(), s.height());
185}
186
187// *this = *this * translation
188AffineTransform& AffineTransform::translate(double tx, double ty)
189{
190 if (isIdentityOrTranslation()) {
191 m_transform[4] += tx;
192 m_transform[5] += ty;
193 return *this;
194 }
195
196 m_transform[4] += tx * m_transform[0] + ty * m_transform[2];
197 m_transform[5] += tx * m_transform[1] + ty * m_transform[3];
198 return *this;
199}
200
201AffineTransform& AffineTransform::translate(const FloatPoint& t)
202{
203 return translate(t.x(), t.y());
204}
205
206AffineTransform& AffineTransform::translate(const FloatSize& t)
207{
208 return translate(t.width(), t.height());
209}
210
211AffineTransform& AffineTransform::rotateFromVector(double x, double y)
212{
213 return rotate(rad2deg(atan2(y, x)));
214}
215
216AffineTransform& AffineTransform::flipX()
217{
218 return scale(-1, 1);
219}
220
221AffineTransform& AffineTransform::flipY()
222{
223 return scale(1, -1);
224}
225
226AffineTransform& AffineTransform::shear(double sx, double sy)
227{
228 double a = m_transform[0];
229 double b = m_transform[1];
230
231 m_transform[0] += sy * m_transform[2];
232 m_transform[1] += sy * m_transform[3];
233 m_transform[2] += sx * a;
234 m_transform[3] += sx * b;
235
236 return *this;
237}
238
239AffineTransform& AffineTransform::skew(double angleX, double angleY)
240{
241 return shear(tan(deg2rad(angleX)), tan(deg2rad(angleY)));
242}
243
244AffineTransform& AffineTransform::skewX(double angle)
245{
246 return shear(tan(deg2rad(angle)), 0);
247}
248
249AffineTransform& AffineTransform::skewY(double angle)
250{
251 return shear(0, tan(deg2rad(angle)));
252}
253
254AffineTransform makeMapBetweenRects(const FloatRect& source, const FloatRect& dest)
255{
256 AffineTransform transform;
257 transform.translate(dest.x() - source.x(), dest.y() - source.y());
258 transform.scale(dest.size() / source.size());
259 return transform;
260}
261
262void AffineTransform::map(double x, double y, double& x2, double& y2) const
263{
264 x2 = (m_transform[0] * x + m_transform[2] * y + m_transform[4]);
265 y2 = (m_transform[1] * x + m_transform[3] * y + m_transform[5]);
266}
267
268IntPoint AffineTransform::mapPoint(const IntPoint& point) const
269{
270 double x2, y2;
271 map(point.x(), point.y(), x2, y2);
272
273 // Round the point.
274 return IntPoint(lround(x2), lround(y2));
275}
276
277FloatPoint AffineTransform::mapPoint(const FloatPoint& point) const
278{
279 double x2, y2;
280 map(point.x(), point.y(), x2, y2);
281
282 return FloatPoint(narrowPrecisionToFloat(x2), narrowPrecisionToFloat(y2));
283}
284
285IntSize AffineTransform::mapSize(const IntSize& size) const
286{
287 double width2 = size.width() * xScale();
288 double height2 = size.height() * yScale();
289
290 return IntSize(lround(width2), lround(height2));
291}
292
293FloatSize AffineTransform::mapSize(const FloatSize& size) const
294{
295 double width2 = size.width() * xScale();
296 double height2 = size.height() * yScale();
297
298 return FloatSize(narrowPrecisionToFloat(width2), narrowPrecisionToFloat(height2));
299}
300
301IntRect AffineTransform::mapRect(const IntRect &rect) const
302{
303 return enclosingIntRect(mapRect(FloatRect(rect)));
304}
305
306FloatRect AffineTransform::mapRect(const FloatRect& rect) const
307{
308 if (isIdentityOrTranslation()) {
309 FloatRect mappedRect(rect);
310 mappedRect.move(narrowPrecisionToFloat(m_transform[4]), narrowPrecisionToFloat(m_transform[5]));
311 return mappedRect;
312 }
313
314 FloatQuad result;
315 result.setP1(mapPoint(rect.location()));
316 result.setP2(mapPoint(FloatPoint(rect.maxX(), rect.y())));
317 result.setP3(mapPoint(FloatPoint(rect.maxX(), rect.maxY())));
318 result.setP4(mapPoint(FloatPoint(rect.x(), rect.maxY())));
319 return result.boundingBox();
320}
321
322FloatQuad AffineTransform::mapQuad(const FloatQuad& q) const
323{
324 if (isIdentityOrTranslation()) {
325 FloatQuad mappedQuad(q);
326 mappedQuad.move(narrowPrecisionToFloat(m_transform[4]), narrowPrecisionToFloat(m_transform[5]));
327 return mappedQuad;
328 }
329
330 FloatQuad result;
331 result.setP1(mapPoint(q.p1()));
332 result.setP2(mapPoint(q.p2()));
333 result.setP3(mapPoint(q.p3()));
334 result.setP4(mapPoint(q.p4()));
335 return result;
336}
337
338Region AffineTransform::mapRegion(const Region& region) const
339{
340 if (isIdentityOrTranslation()) {
341 Region mappedRegion(region);
342 mappedRegion.translate(roundedIntSize(FloatSize(narrowPrecisionToFloat(m_transform[4]), narrowPrecisionToFloat(m_transform[5]))));
343 return mappedRegion;
344 }
345
346 Region mappedRegion;
347 for (auto& rect : region.rects())
348 mappedRegion.unite(mapRect(rect));
349
350 return mappedRegion;
351}
352
353void AffineTransform::blend(const AffineTransform& from, double progress)
354{
355 DecomposedType srA, srB;
356
357 from.decompose(srA);
358 this->decompose(srB);
359
360 // If x-axis of one is flipped, and y-axis of the other, convert to an unflipped rotation.
361 if ((srA.scaleX < 0 && srB.scaleY < 0) || (srA.scaleY < 0 && srB.scaleX < 0)) {
362 srA.scaleX = -srA.scaleX;
363 srA.scaleY = -srA.scaleY;
364 srA.angle += srA.angle < 0 ? piDouble : -piDouble;
365 }
366
367 // Don't rotate the long way around.
368 srA.angle = fmod(srA.angle, 2 * piDouble);
369 srB.angle = fmod(srB.angle, 2 * piDouble);
370
371 if (fabs(srA.angle - srB.angle) > piDouble) {
372 if (srA.angle > srB.angle)
373 srA.angle -= piDouble * 2;
374 else
375 srB.angle -= piDouble * 2;
376 }
377
378 srA.scaleX += progress * (srB.scaleX - srA.scaleX);
379 srA.scaleY += progress * (srB.scaleY - srA.scaleY);
380 srA.angle += progress * (srB.angle - srA.angle);
381 srA.remainderA += progress * (srB.remainderA - srA.remainderA);
382 srA.remainderB += progress * (srB.remainderB - srA.remainderB);
383 srA.remainderC += progress * (srB.remainderC - srA.remainderC);
384 srA.remainderD += progress * (srB.remainderD - srA.remainderD);
385 srA.translateX += progress * (srB.translateX - srA.translateX);
386 srA.translateY += progress * (srB.translateY - srA.translateY);
387
388 this->recompose(srA);
389}
390
391TransformationMatrix AffineTransform::toTransformationMatrix() const
392{
393 return TransformationMatrix(m_transform[0], m_transform[1], m_transform[2],
394 m_transform[3], m_transform[4], m_transform[5]);
395}
396
397bool AffineTransform::decompose(DecomposedType& decomp) const
398{
399 AffineTransform m(*this);
400
401 // Compute scaling factors
402 double sx = xScale();
403 double sy = yScale();
404
405 // Compute cross product of transformed unit vectors. If negative,
406 // one axis was flipped.
407 if (m.a() * m.d() - m.c() * m.b() < 0) {
408 // Flip axis with minimum unit vector dot product
409 if (m.a() < m.d())
410 sx = -sx;
411 else
412 sy = -sy;
413 }
414
415 // Remove scale from matrix
416 m.scale(1 / sx, 1 / sy);
417
418 // Compute rotation
419 double angle = atan2(m.b(), m.a());
420
421 // Remove rotation from matrix
422 m.rotate(rad2deg(-angle));
423
424 // Return results
425 decomp.scaleX = sx;
426 decomp.scaleY = sy;
427 decomp.angle = angle;
428 decomp.remainderA = m.a();
429 decomp.remainderB = m.b();
430 decomp.remainderC = m.c();
431 decomp.remainderD = m.d();
432 decomp.translateX = m.e();
433 decomp.translateY = m.f();
434
435 return true;
436}
437
438void AffineTransform::recompose(const DecomposedType& decomp)
439{
440 this->setA(decomp.remainderA);
441 this->setB(decomp.remainderB);
442 this->setC(decomp.remainderC);
443 this->setD(decomp.remainderD);
444 this->setE(decomp.translateX);
445 this->setF(decomp.translateY);
446 this->rotate(rad2deg(decomp.angle));
447 this->scale(decomp.scaleX, decomp.scaleY);
448}
449
450TextStream& operator<<(TextStream& ts, const AffineTransform& transform)
451{
452 if (transform.isIdentity())
453 ts << "identity";
454 else
455 ts << "{m=(("
456 << transform.a() << "," << transform.b()
457 << ")("
458 << transform.c() << "," << transform.d()
459 << ")) t=("
460 << transform.e() << "," << transform.f()
461 << ")}";
462
463 return ts;
464}
465
466}
467