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