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