• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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