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