2009-07-01 David Levin <levin@chromium.org>
[WebKit-https.git] / WebCore / svg / SVGTransformDistance.cpp
1 /*
2  Copyright (C) 2007 Eric Seidel <eric@webkit.org>
3  
4  This file is part of the WebKit project
5  
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Library General Public
8  License as published by the Free Software Foundation; either
9  version 2 of the License, or (at your option) any later version.
10  
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  Library General Public License for more details.
15  
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB.  If not, write to
18  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  Boston, MA 02110-1301, USA.
20  */
21
22 #include "config.h"
23 #if ENABLE(SVG)
24 #include "SVGTransformDistance.h"
25
26 #include "FloatConversion.h"
27 #include "FloatPoint.h"
28 #include "FloatSize.h"
29 #include "SVGTransform.h"
30
31 #include <math.h>
32
33 namespace WebCore {
34     
35 SVGTransformDistance::SVGTransformDistance()
36     : m_type(SVGTransform::SVG_TRANSFORM_UNKNOWN)
37     , m_angle(0)
38     , m_cx(0)
39     , m_cy(0)
40 {
41 }
42
43 SVGTransformDistance::SVGTransformDistance(SVGTransform::SVGTransformType type, float angle, float cx, float cy, const TransformationMatrix& transform)
44     : m_type(type)
45     , m_angle(angle)
46     , m_cx(cx)
47     , m_cy(cy)
48     , m_transform(transform)
49 {
50 }
51
52 SVGTransformDistance::SVGTransformDistance(const SVGTransform& fromSVGTransform, const SVGTransform& toSVGTransform)
53     : m_type(fromSVGTransform.type())
54     , m_angle(0)
55     , m_cx(0)
56     , m_cy(0)
57 {
58     ASSERT(m_type == toSVGTransform.type());
59     
60     switch (m_type) {
61     case SVGTransform::SVG_TRANSFORM_UNKNOWN:
62         return;
63     case SVGTransform::SVG_TRANSFORM_MATRIX:
64         // FIXME: need to be able to subtract to matrices
65         return;
66     case SVGTransform::SVG_TRANSFORM_ROTATE:
67     {
68         FloatSize centerDistance = toSVGTransform.rotationCenter() - fromSVGTransform.rotationCenter();
69         m_angle = toSVGTransform.angle() - fromSVGTransform.angle();
70         m_cx = centerDistance.width();
71         m_cy = centerDistance.height();
72         return;
73     }
74     case SVGTransform::SVG_TRANSFORM_TRANSLATE:
75     {
76         FloatSize translationDistance = toSVGTransform.translate() - fromSVGTransform.translate();
77         m_transform.translate(translationDistance.width(), translationDistance.height());
78         return;
79     }
80     case SVGTransform::SVG_TRANSFORM_SCALE:
81     {
82         float scaleX = toSVGTransform.scale().width() - fromSVGTransform.scale().width();        
83         float scaleY = toSVGTransform.scale().height() - fromSVGTransform.scale().height();
84         m_transform.scaleNonUniform(scaleX, scaleY);
85         return;
86     }
87     case SVGTransform::SVG_TRANSFORM_SKEWX:
88     case SVGTransform::SVG_TRANSFORM_SKEWY:
89         m_angle = toSVGTransform.angle() - fromSVGTransform.angle();
90         return;
91     }
92 }
93
94 SVGTransformDistance SVGTransformDistance::scaledDistance(float scaleFactor) const
95 {
96     switch (m_type) {
97     case SVGTransform::SVG_TRANSFORM_UNKNOWN:
98         return SVGTransformDistance();
99     case SVGTransform::SVG_TRANSFORM_ROTATE:
100         return SVGTransformDistance(m_type, m_angle * scaleFactor, m_cx * scaleFactor, m_cy * scaleFactor, TransformationMatrix());
101     case SVGTransform::SVG_TRANSFORM_SCALE:
102     case SVGTransform::SVG_TRANSFORM_MATRIX:
103         return SVGTransformDistance(m_type, m_angle * scaleFactor, m_cx * scaleFactor, m_cy * scaleFactor, TransformationMatrix(m_transform).scale(scaleFactor));
104     case SVGTransform::SVG_TRANSFORM_TRANSLATE:
105     {
106         TransformationMatrix newTransform(m_transform);
107         newTransform.setE(m_transform.e() * scaleFactor);
108         newTransform.setF(m_transform.f() * scaleFactor);
109         return SVGTransformDistance(m_type, 0, 0, 0, newTransform);
110     }
111     case SVGTransform::SVG_TRANSFORM_SKEWX:
112     case SVGTransform::SVG_TRANSFORM_SKEWY:
113         return SVGTransformDistance(m_type, m_angle * scaleFactor, m_cx * scaleFactor, m_cy * scaleFactor, TransformationMatrix());
114     }
115     
116     ASSERT_NOT_REACHED();
117     return SVGTransformDistance();
118 }
119
120 SVGTransform SVGTransformDistance::addSVGTransforms(const SVGTransform& first, const SVGTransform& second)
121 {
122     ASSERT(first.type() == second.type());
123     
124     SVGTransform transform;
125     
126     switch (first.type()) {
127     case SVGTransform::SVG_TRANSFORM_UNKNOWN:
128         return SVGTransform();
129     case SVGTransform::SVG_TRANSFORM_ROTATE:
130     {
131         transform.setRotate(first.angle() + second.angle(), first.rotationCenter().x() + second.rotationCenter().x(),
132                             first.rotationCenter().y() + second.rotationCenter().y());
133         return transform;
134     }
135     case SVGTransform::SVG_TRANSFORM_MATRIX:
136         transform.setMatrix(first.matrix() * second.matrix());
137         return transform;
138     case SVGTransform::SVG_TRANSFORM_TRANSLATE:
139     {
140         float dx = first.translate().x() + second.translate().x();
141         float dy = first.translate().y() + second.translate().y();
142         transform.setTranslate(dx, dy);
143         return transform;
144     }
145     case SVGTransform::SVG_TRANSFORM_SCALE:
146     {
147         FloatSize scale = first.scale() + second.scale();
148         transform.setScale(scale.width(), scale.height());
149         return transform;
150     }
151     case SVGTransform::SVG_TRANSFORM_SKEWX:
152         transform.setSkewX(first.angle() + second.angle());
153         return transform;
154     case SVGTransform::SVG_TRANSFORM_SKEWY:
155         transform.setSkewY(first.angle() + second.angle());
156         return transform;
157     }
158     
159     ASSERT_NOT_REACHED();
160     return SVGTransform();
161 }
162
163 void SVGTransformDistance::addSVGTransform(const SVGTransform& transform, bool absoluteValue)
164 {
165     // If this is the first add, set the type for this SVGTransformDistance
166     if (m_type == SVGTransform::SVG_TRANSFORM_UNKNOWN)
167         m_type = transform.type();
168     
169     ASSERT(m_type == transform.type());
170     
171     switch (m_type) {
172     case SVGTransform::SVG_TRANSFORM_UNKNOWN:
173         return;
174     case SVGTransform::SVG_TRANSFORM_MATRIX:
175         m_transform *= transform.matrix(); // FIXME: what does 'distance' between two transforms mean?  how should we respect 'absoluteValue' here?
176         return;
177     case SVGTransform::SVG_TRANSFORM_ROTATE:
178         m_angle += absoluteValue ? fabsf(transform.angle()) : transform.angle();
179         m_cx += absoluteValue ? fabsf(transform.rotationCenter().x()) : transform.rotationCenter().x();
180         m_cy += absoluteValue ? fabsf(transform.rotationCenter().y()) : transform.rotationCenter().y();
181         // fall through
182     case SVGTransform::SVG_TRANSFORM_TRANSLATE:
183     {
184         float dx = absoluteValue ? fabsf(transform.translate().x()) : transform.translate().x();
185         float dy = absoluteValue ? fabsf(transform.translate().y()) : transform.translate().y();
186         m_transform.translate(dx, dy);
187         return;
188     }
189     case SVGTransform::SVG_TRANSFORM_SCALE:
190     {
191         float scaleX = absoluteValue ? fabsf(transform.scale().width()) : transform.scale().width();
192         float scaleY = absoluteValue ? fabsf(transform.scale().height()) : transform.scale().height();
193         m_transform.scaleNonUniform(scaleX, scaleY);
194         return;
195     }
196     case SVGTransform::SVG_TRANSFORM_SKEWX:
197     case SVGTransform::SVG_TRANSFORM_SKEWY:
198         m_angle += absoluteValue ? fabsf(transform.angle()) : transform.angle();
199         return;
200     }
201     
202     ASSERT_NOT_REACHED();
203     return;
204 }
205
206 SVGTransform SVGTransformDistance::addToSVGTransform(const SVGTransform& transform) const
207 {
208     ASSERT(m_type == transform.type() || transform == SVGTransform());
209     
210     SVGTransform newTransform(transform);
211     
212     switch (m_type) {
213     case SVGTransform::SVG_TRANSFORM_UNKNOWN:
214         return SVGTransform();
215     case SVGTransform::SVG_TRANSFORM_MATRIX:
216         return SVGTransform(transform.matrix() * m_transform);
217     case SVGTransform::SVG_TRANSFORM_TRANSLATE:
218     {
219         FloatPoint translation = transform.translate();
220         translation += FloatSize::narrowPrecision(m_transform.e(), m_transform.f());
221         newTransform.setTranslate(translation.x(), translation.y());
222         return newTransform;
223     }
224     case SVGTransform::SVG_TRANSFORM_SCALE:
225     {
226         FloatSize scale = transform.scale();
227         scale += FloatSize::narrowPrecision(m_transform.a(), m_transform.d());
228         newTransform.setScale(scale.width(), scale.height());
229         return newTransform;
230     }
231     case SVGTransform::SVG_TRANSFORM_ROTATE:
232     {
233         // FIXME: I'm not certain the translation is calculated correctly here
234         FloatPoint center = transform.rotationCenter();
235         newTransform.setRotate(transform.angle() + m_angle,
236                                center.x() + m_cx,
237                                center.y() + m_cy);
238         return newTransform;
239     }
240     case SVGTransform::SVG_TRANSFORM_SKEWX:
241         newTransform.setSkewX(transform.angle() + m_angle);
242         return newTransform;
243     case SVGTransform::SVG_TRANSFORM_SKEWY:
244         newTransform.setSkewY(transform.angle() + m_angle);
245         return newTransform;
246     }
247     
248     ASSERT_NOT_REACHED();
249     return SVGTransform();
250 }
251
252 bool SVGTransformDistance::isZero() const
253 {
254     return (m_transform == TransformationMatrix() && m_angle == 0);
255 }
256
257 float SVGTransformDistance::distance() const
258 {
259     switch (m_type) {
260     case SVGTransform::SVG_TRANSFORM_UNKNOWN:
261         return 0.0f;
262     case SVGTransform::SVG_TRANSFORM_ROTATE:
263         return sqrtf(m_angle * m_angle + m_cx * m_cx + m_cy * m_cy);
264     case SVGTransform::SVG_TRANSFORM_MATRIX:
265         return 0.0f; // I'm not quite sure yet what distance between two matrices means.
266     case SVGTransform::SVG_TRANSFORM_SCALE:
267         return static_cast<float>(sqrt(m_transform.a() * m_transform.a() + m_transform.d() * m_transform.d()));
268     case SVGTransform::SVG_TRANSFORM_TRANSLATE:
269         return static_cast<float>(sqrt(m_transform.e() * m_transform.e() + m_transform.f() * m_transform.f()));
270     case SVGTransform::SVG_TRANSFORM_SKEWX:
271     case SVGTransform::SVG_TRANSFORM_SKEWY:
272         return m_angle;
273     }
274     ASSERT_NOT_REACHED();
275     return 0.0f;
276 }
277
278 }
279
280 #endif