2008-09-08 Chris Marrin <cmarrin@apple.com>
[WebKit-https.git] / WebCore / platform / graphics / AffineTransform.cpp
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 "AffineTransform.h"
28
29 #include "FloatRect.h"
30 #include "IntRect.h"
31
32 #include <wtf/MathExtras.h>
33
34 namespace WebCore {
35
36 static void affineTransformDecompose(const AffineTransform& matrix, double sr[9])
37 {
38     AffineTransform m(matrix);
39
40     // Compute scaling factors
41     double sx = sqrt(m.a() * m.a() + m.b() * m.b());
42     double sy = sqrt(m.c() * m.c() + m.d() * m.d());
43
44     /* Compute cross product of transformed unit vectors. If negative,
45         one axis was flipped. */
46
47     if (m.a() * m.d() - m.c() * m.b() < 0.0) {
48         // Flip axis with minimum unit vector dot product
49
50         if (m.a() < m.d())
51             sx = -sx;
52         else
53             sy = -sy;
54     }
55
56     // Remove scale from matrix
57
58     m.scale(1.0 / sx, 1.0 / sy);
59
60     // Compute rotation
61
62     double angle = atan2(m.b(), m.a());
63
64     // Remove rotation from matrix
65
66     m.rotate(rad2deg(-angle));
67
68     // Return results
69
70     sr[0] = sx; sr[1] = sy; sr[2] = angle;
71     sr[3] = m.a(); sr[4] = m.b();
72     sr[5] = m.c(); sr[6] = m.d();
73     sr[7] = m.e(); sr[8] = m.f();
74 }
75
76 static void affineTransformCompose(AffineTransform& m, const double sr[9])
77 {
78     m.setA(sr[3]);
79     m.setB(sr[4]);
80     m.setC(sr[5]);
81     m.setD(sr[6]);
82     m.setE(sr[7]);
83     m.setF(sr[8]);
84     m.rotate(rad2deg(sr[2]));
85     m.scale(sr[0], sr[1]);
86 }
87
88 bool AffineTransform::isInvertible() const
89 {
90     return det() != 0.0;
91 }
92
93 AffineTransform& AffineTransform::multiply(const AffineTransform& other)
94 {
95     return (*this) *= other;
96 }
97
98 AffineTransform& AffineTransform::scale(double s)
99 {
100     return scale(s, s);
101 }
102
103 AffineTransform& AffineTransform::scaleNonUniform(double sx, double sy)
104 {
105     return scale(sx, sy);
106 }
107
108 AffineTransform& AffineTransform::rotateFromVector(double x, double y)
109 {
110     return rotate(rad2deg(atan2(y, x)));
111 }
112
113 AffineTransform& AffineTransform::flipX()
114 {
115     return scale(-1.0f, 1.0f);
116 }
117
118 AffineTransform& AffineTransform::flipY()
119 {
120     return scale(1.0f, -1.0f);
121 }
122
123 AffineTransform& AffineTransform::skew(double angleX, double angleY)
124 {
125     return shear(tan(deg2rad(angleX)), tan(deg2rad(angleY)));
126 }
127
128 AffineTransform& AffineTransform::skewX(double angle)
129 {
130     return shear(tan(deg2rad(angle)), 0.0f);
131 }
132
133 AffineTransform& AffineTransform::skewY(double angle)
134 {
135     return shear(0.0f, tan(deg2rad(angle)));
136 }
137
138 IntPoint AffineTransform::mapPoint(const IntPoint& point) const
139 {
140     double x2, y2;
141     map(point.x(), point.y(), &x2, &y2);
142     
143     // Round the point.
144     return IntPoint(lround(x2), lround(y2));
145 }
146
147 FloatPoint AffineTransform::mapPoint(const FloatPoint& point) const
148 {
149     double x2, y2;
150     map(point.x(), point.y(), &x2, &y2);
151
152     return FloatPoint(static_cast<float>(x2), static_cast<float>(y2));
153 }
154
155 void AffineTransform::blend(const AffineTransform& from, double progress)
156 {
157     double srA[9], srB[9];
158
159     affineTransformDecompose(from, srA);
160     affineTransformDecompose(*this, srB);
161
162     // If x-axis of one is flipped, and y-axis of the other, convert to an unflipped rotation.
163     if ((srA[0] < 0.0 && srB[1] < 0.0) || (srA[1] < 0.0 &&  srB[0] < 0.0)) {
164         srA[0] = -srA[0];
165         srA[1] = -srA[1];
166         srA[2] += srA[2] < 0 ? piDouble : -piDouble;
167     }
168
169     // Don't rotate the long way around.
170     srA[2] = fmod(srA[2], 2.0 * piDouble);
171     srB[2] = fmod(srB[2], 2.0 * piDouble);
172
173     if (fabs (srA[2] - srB[2]) > piDouble) {
174         if (srA[2] > srB[2])
175             srA[2] -= piDouble * 2.0;
176         else
177             srB[2] -= piDouble * 2.0;
178     }
179
180     for (int i = 0; i < 9; i++)
181         srA[i] = srA[i] + progress * (srB[i] - srA[i]);
182
183     affineTransformCompose(*this, srA);
184 }
185
186 }