1 /*
2 * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "config.h"
27 #include "TransformationMatrix.h"
28
29 #include "FloatRect.h"
30 #include "FloatQuad.h"
31 #include "IntRect.h"
32
33 #include <wtf/MathExtras.h>
34
35 namespace WebCore {
36
affineTransformDecompose(const TransformationMatrix & matrix,double sr[9])37 static void affineTransformDecompose(const TransformationMatrix& matrix, double sr[9])
38 {
39 TransformationMatrix m(matrix);
40
41 // Compute scaling factors
42 double sx = sqrt(m.a() * m.a() + m.b() * m.b());
43 double sy = sqrt(m.c() * m.c() + m.d() * m.d());
44
45 /* Compute cross product of transformed unit vectors. If negative,
46 one axis was flipped. */
47
48 if (m.a() * m.d() - m.c() * m.b() < 0.0) {
49 // Flip axis with minimum unit vector dot product
50
51 if (m.a() < m.d())
52 sx = -sx;
53 else
54 sy = -sy;
55 }
56
57 // Remove scale from matrix
58
59 m.scale(1.0 / sx, 1.0 / sy);
60
61 // Compute rotation
62
63 double angle = atan2(m.b(), m.a());
64
65 // Remove rotation from matrix
66
67 m.rotate(rad2deg(-angle));
68
69 // Return results
70
71 sr[0] = sx; sr[1] = sy; sr[2] = angle;
72 sr[3] = m.a(); sr[4] = m.b();
73 sr[5] = m.c(); sr[6] = m.d();
74 sr[7] = m.e(); sr[8] = m.f();
75 }
76
affineTransformCompose(TransformationMatrix & m,const double sr[9])77 static void affineTransformCompose(TransformationMatrix& m, const double sr[9])
78 {
79 m.setA(sr[3]);
80 m.setB(sr[4]);
81 m.setC(sr[5]);
82 m.setD(sr[6]);
83 m.setE(sr[7]);
84 m.setF(sr[8]);
85 m.rotate(rad2deg(sr[2]));
86 m.scale(sr[0], sr[1]);
87 }
88
isInvertible() const89 bool TransformationMatrix::isInvertible() const
90 {
91 return det() != 0.0;
92 }
93
multiply(const TransformationMatrix & other)94 TransformationMatrix& TransformationMatrix::multiply(const TransformationMatrix& other)
95 {
96 return (*this) *= other;
97 }
98
scale(double s)99 TransformationMatrix& TransformationMatrix::scale(double s)
100 {
101 return scale(s, s);
102 }
103
scaleNonUniform(double sx,double sy)104 TransformationMatrix& TransformationMatrix::scaleNonUniform(double sx, double sy)
105 {
106 return scale(sx, sy);
107 }
108
rotateFromVector(double x,double y)109 TransformationMatrix& TransformationMatrix::rotateFromVector(double x, double y)
110 {
111 return rotate(rad2deg(atan2(y, x)));
112 }
113
flipX()114 TransformationMatrix& TransformationMatrix::flipX()
115 {
116 return scale(-1.0f, 1.0f);
117 }
118
flipY()119 TransformationMatrix& TransformationMatrix::flipY()
120 {
121 return scale(1.0f, -1.0f);
122 }
123
skew(double angleX,double angleY)124 TransformationMatrix& TransformationMatrix::skew(double angleX, double angleY)
125 {
126 return shear(tan(deg2rad(angleX)), tan(deg2rad(angleY)));
127 }
128
skewX(double angle)129 TransformationMatrix& TransformationMatrix::skewX(double angle)
130 {
131 return shear(tan(deg2rad(angle)), 0.0f);
132 }
133
skewY(double angle)134 TransformationMatrix& TransformationMatrix::skewY(double angle)
135 {
136 return shear(0.0f, tan(deg2rad(angle)));
137 }
138
makeMapBetweenRects(const FloatRect & source,const FloatRect & dest)139 TransformationMatrix makeMapBetweenRects(const FloatRect& source, const FloatRect& dest)
140 {
141 TransformationMatrix transform;
142 transform.translate(dest.x() - source.x(), dest.y() - source.y());
143 transform.scale(dest.width() / source.width(), dest.height() / source.height());
144 return transform;
145 }
146
mapPoint(const IntPoint & point) const147 IntPoint TransformationMatrix::mapPoint(const IntPoint& point) const
148 {
149 double x2, y2;
150 map(point.x(), point.y(), &x2, &y2);
151
152 // Round the point.
153 return IntPoint(lround(x2), lround(y2));
154 }
155
mapPoint(const FloatPoint & point) const156 FloatPoint TransformationMatrix::mapPoint(const FloatPoint& point) const
157 {
158 double x2, y2;
159 map(point.x(), point.y(), &x2, &y2);
160
161 return FloatPoint(static_cast<float>(x2), static_cast<float>(y2));
162 }
163
mapQuad(const FloatQuad & quad) const164 FloatQuad TransformationMatrix::mapQuad(const FloatQuad& quad) const
165 {
166 // FIXME: avoid 4 seperate library calls. Point mapping really needs
167 // to be platform-independent code.
168 return FloatQuad(mapPoint(quad.p1()),
169 mapPoint(quad.p2()),
170 mapPoint(quad.p3()),
171 mapPoint(quad.p4()));
172 }
173
blend(const TransformationMatrix & from,double progress)174 void TransformationMatrix::blend(const TransformationMatrix& from, double progress)
175 {
176 double srA[9], srB[9];
177
178 affineTransformDecompose(from, srA);
179 affineTransformDecompose(*this, srB);
180
181 // If x-axis of one is flipped, and y-axis of the other, convert to an unflipped rotation.
182 if ((srA[0] < 0.0 && srB[1] < 0.0) || (srA[1] < 0.0 && srB[0] < 0.0)) {
183 srA[0] = -srA[0];
184 srA[1] = -srA[1];
185 srA[2] += srA[2] < 0 ? piDouble : -piDouble;
186 }
187
188 // Don't rotate the long way around.
189 srA[2] = fmod(srA[2], 2.0 * piDouble);
190 srB[2] = fmod(srB[2], 2.0 * piDouble);
191
192 if (fabs(srA[2] - srB[2]) > piDouble) {
193 if (srA[2] > srB[2])
194 srA[2] -= piDouble * 2.0;
195 else
196 srB[2] -= piDouble * 2.0;
197 }
198
199 for (int i = 0; i < 9; i++)
200 srA[i] = srA[i] + progress * (srB[i] - srA[i]);
201
202 affineTransformCompose(*this, srA);
203 }
204
205 }
206