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