JavaScriptCore:
[WebKit-https.git] / WebCore / ksvg2 / 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., 59 Temple Place - Suite 330,
19  Boston, MA 02111-1307, USA.
20  */
21
22 #include "config.h"
23 #if ENABLE(SVG)
24 #include "SVGTransformDistance.h"
25
26 #include "FloatPoint.h"
27 #include "FloatSize.h"
28 #include "SVGTransform.h"
29
30 #include <math.h>
31
32 namespace WebCore {
33     
34 SVGTransformDistance::SVGTransformDistance()
35     : m_type(SVGTransform::SVG_TRANSFORM_UNKNOWN)
36     , m_angle(0)
37 {
38 }
39
40 SVGTransformDistance::SVGTransformDistance(SVGTransform::SVGTransformType type, double angle, double cx, double cy, const AffineTransform& transform)
41     : m_type(type)
42     , m_angle(angle)
43     , m_cx(cx)
44     , m_cy(cy)
45     , m_transform(transform)
46 {
47 }
48
49 SVGTransformDistance::SVGTransformDistance(const SVGTransform& fromSVGTransform, const SVGTransform& toSVGTransform)
50     : m_type(fromSVGTransform.type())
51     , m_angle(0)
52     , m_cx(0)
53     , m_cy(0)
54 {
55     ASSERT(m_type == toSVGTransform.type());
56     
57     switch (m_type) {
58     case SVGTransform::SVG_TRANSFORM_UNKNOWN:
59         return;
60     case SVGTransform::SVG_TRANSFORM_MATRIX:
61         // FIXME: need to be able to subtract to matrices
62         return;
63     case SVGTransform::SVG_TRANSFORM_ROTATE:
64     {
65         FloatSize centerDistance = toSVGTransform.rotationCenter() - fromSVGTransform.rotationCenter();
66         m_angle = toSVGTransform.angle() - fromSVGTransform.angle();
67         m_cx = centerDistance.width();
68         m_cy = centerDistance.height();
69         return;
70     }
71     case SVGTransform::SVG_TRANSFORM_TRANSLATE:
72     {
73         FloatSize translationDistance = toSVGTransform.translate() - fromSVGTransform.translate();
74         m_transform.translate(translationDistance.width(), translationDistance.height());
75         return;
76     }
77     case SVGTransform::SVG_TRANSFORM_SCALE:
78     {
79         float scaleX = fromSVGTransform.scale().width() != 0 ? toSVGTransform.scale().width() / fromSVGTransform.scale().width() : toSVGTransform.scale().width() / 0.00001f;
80         float scaleY = fromSVGTransform.scale().height() != 0 ? toSVGTransform.scale().height() / fromSVGTransform.scale().height() : toSVGTransform.scale().height() / 0.00001f;
81         m_transform.scale(scaleX, scaleY);
82         return;
83     }
84     case SVGTransform::SVG_TRANSFORM_SKEWX:
85     case SVGTransform::SVG_TRANSFORM_SKEWY:
86         m_angle = toSVGTransform.angle() - fromSVGTransform.angle();
87         return;
88     }
89 }
90
91 SVGTransformDistance SVGTransformDistance::scaledDistance(float scaleFactor) const
92 {
93     switch (m_type) {
94     case SVGTransform::SVG_TRANSFORM_UNKNOWN:
95         return SVGTransformDistance();
96     case SVGTransform::SVG_TRANSFORM_ROTATE:
97         return SVGTransformDistance(m_type, m_angle * scaleFactor, m_cx * scaleFactor, m_cy * scaleFactor, AffineTransform());
98     case SVGTransform::SVG_TRANSFORM_SCALE:
99     case SVGTransform::SVG_TRANSFORM_MATRIX:
100         return SVGTransformDistance(m_type, m_angle * scaleFactor, m_cx * scaleFactor, m_cy * scaleFactor, AffineTransform(m_transform).scale(scaleFactor));
101     case SVGTransform::SVG_TRANSFORM_TRANSLATE:
102     {
103         AffineTransform newTransform(m_transform);
104         newTransform.setE(m_transform.e() * scaleFactor);
105         newTransform.setF(m_transform.f() * scaleFactor);
106         return SVGTransformDistance(m_type, 0, 0, 0, newTransform);
107     }
108     case SVGTransform::SVG_TRANSFORM_SKEWX:
109     case SVGTransform::SVG_TRANSFORM_SKEWY:
110         return SVGTransformDistance(m_type, m_angle * scaleFactor, m_cx * scaleFactor, m_cy * scaleFactor, AffineTransform());
111     }
112     
113     ASSERT_NOT_REACHED();
114     return SVGTransformDistance();
115 }
116
117 SVGTransform SVGTransformDistance::addSVGTransforms(const SVGTransform& first, const SVGTransform& second)
118 {
119     ASSERT(first.type() == second.type());
120     
121     SVGTransform transform;
122     
123     switch (first.type()) {
124     case SVGTransform::SVG_TRANSFORM_UNKNOWN:
125         return SVGTransform();
126     case SVGTransform::SVG_TRANSFORM_ROTATE:
127     {
128         transform.setRotate(first.angle() + second.angle(), first.rotationCenter().x() + second.rotationCenter().x(),
129                             first.rotationCenter().y() + second.rotationCenter().y());
130         return transform;
131     }
132     case SVGTransform::SVG_TRANSFORM_MATRIX:
133         transform.setMatrix(first.matrix() * second.matrix());
134         return transform;
135     case SVGTransform::SVG_TRANSFORM_TRANSLATE:
136     {
137         float dx = first.translate().x() + second.translate().x();
138         float dy = first.translate().y() + second.translate().y();
139         transform.setTranslate(dx, dy);
140         return transform;
141     }
142     case SVGTransform::SVG_TRANSFORM_SCALE:
143     {
144         FloatSize scale = first.scale() + second.scale();
145         transform.setScale(scale.width(), scale.height());
146         return transform;
147     }
148     case SVGTransform::SVG_TRANSFORM_SKEWX:
149         transform.setSkewX(first.angle() + second.angle());
150         return transform;
151     case SVGTransform::SVG_TRANSFORM_SKEWY:
152         transform.setSkewY(first.angle() + second.angle());
153         return transform;
154     }
155     
156     ASSERT_NOT_REACHED();
157     return SVGTransform();
158 }
159
160 void SVGTransformDistance::addSVGTransform(const SVGTransform& transform, bool absoluteValue)
161 {
162     // If this is the first add, set the type for this SVGTransformDistance
163     if (m_type == SVGTransform::SVG_TRANSFORM_UNKNOWN)
164         m_type = transform.type();
165     
166     ASSERT(m_type == transform.type());
167     
168     switch (m_type) {
169     case SVGTransform::SVG_TRANSFORM_UNKNOWN:
170         return;
171     case SVGTransform::SVG_TRANSFORM_MATRIX:
172         m_transform *= transform.matrix(); // FIXME: what does 'distance' between two transforms mean?  how should we respect 'absoluteValue' here?
173         return;
174     case SVGTransform::SVG_TRANSFORM_ROTATE:
175         m_angle += absoluteValue ? fabsf(transform.angle()) : transform.angle();
176         m_cx += absoluteValue ? fabsf(transform.rotationCenter().x()) : transform.rotationCenter().x();
177         m_cy += absoluteValue ? fabsf(transform.rotationCenter().y()) : transform.rotationCenter().y();
178         // fall through
179     case SVGTransform::SVG_TRANSFORM_TRANSLATE:
180     {
181         float dx = absoluteValue ? fabsf(transform.translate().x()) : transform.translate().x();
182         float dy = absoluteValue ? fabsf(transform.translate().y()) : transform.translate().y();
183         m_transform.translate(dx, dy);
184         return;
185     }
186     case SVGTransform::SVG_TRANSFORM_SCALE:
187     {
188         float scaleX = absoluteValue ? fabsf(transform.scale().width()) : transform.scale().width();
189         float scaleY = absoluteValue ? fabsf(transform.scale().height()) : transform.scale().height();
190         m_transform.scale(scaleX, scaleY);
191         return;
192     }
193     case SVGTransform::SVG_TRANSFORM_SKEWX:
194     case SVGTransform::SVG_TRANSFORM_SKEWY:
195         m_angle += absoluteValue ? fabsf(transform.angle()) : transform.angle();
196         return;
197     }
198     
199     ASSERT_NOT_REACHED();
200     return;
201 }
202
203 SVGTransform SVGTransformDistance::addToSVGTransform(const SVGTransform& transform) const
204 {
205     ASSERT(m_type == transform.type() || transform == SVGTransform());
206     
207     SVGTransform newTransform(transform);
208     
209     switch (m_type) {
210     case SVGTransform::SVG_TRANSFORM_UNKNOWN:
211         return SVGTransform();
212     case SVGTransform::SVG_TRANSFORM_MATRIX:
213         return SVGTransform(transform.matrix() * m_transform);
214     case SVGTransform::SVG_TRANSFORM_TRANSLATE:
215     {
216         FloatPoint translation = transform.translate();
217         translation += FloatSize(m_transform.e(), m_transform.f());
218         newTransform.setTranslate(translation.x(), translation.y());
219         return newTransform;
220     }
221     case SVGTransform::SVG_TRANSFORM_SCALE:
222     {
223         FloatSize scale = transform.scale();
224         scale += FloatSize(m_transform.a(), m_transform.d());
225         newTransform.setScale(scale.width(), scale.height());
226         return newTransform;
227     }
228     case SVGTransform::SVG_TRANSFORM_ROTATE:
229     {
230         // FIXME: I'm not certain the translation is calculated correctly here
231         FloatPoint center = transform.rotationCenter();
232         newTransform.setRotate(transform.angle() + m_angle, center.x() + m_cx, center.y() + m_cy);
233         return newTransform;
234     }
235     case SVGTransform::SVG_TRANSFORM_SKEWX:
236         newTransform.setSkewX(transform.angle() + m_angle);
237         return newTransform;
238     case SVGTransform::SVG_TRANSFORM_SKEWY:
239         newTransform.setSkewY(transform.angle() + m_angle);
240         return newTransform;
241     }
242     
243     ASSERT_NOT_REACHED();
244     return SVGTransform();
245 }
246
247 bool SVGTransformDistance::isZero() const
248 {
249     return (m_transform == AffineTransform() && m_angle == 0);
250 }
251
252 float SVGTransformDistance::distance() const
253 {
254     switch (m_type) {
255     case SVGTransform::SVG_TRANSFORM_UNKNOWN:
256         return 0.0f;
257     case SVGTransform::SVG_TRANSFORM_ROTATE:
258         return sqrtf(m_angle * m_angle + m_cx * m_cx + m_cy * m_cy);
259     case SVGTransform::SVG_TRANSFORM_MATRIX:
260         return 0.0f; // I'm not quite sure yet what distance between two matrices means.
261     case SVGTransform::SVG_TRANSFORM_SCALE:
262         return sqrtf(m_transform.a() * m_transform.a() + m_transform.d() * m_transform.d());
263     case SVGTransform::SVG_TRANSFORM_TRANSLATE:
264         return sqrtf(m_transform.e() * m_transform.e() + m_transform.f() * m_transform.f());
265     case SVGTransform::SVG_TRANSFORM_SKEWX:
266     case SVGTransform::SVG_TRANSFORM_SKEWY:
267         return m_angle;
268     }
269     ASSERT_NOT_REACHED();
270     return 0.0f;
271 }
272
273 }
274
275 #endif