1 /*
2 * Copyright (C) 2004, 2005 Nikolas Zimmermann <zimmermann@kde.org>
3 * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #include "config.h"
22 #include "core/svg/SVGTransform.h"
23
24 #include "platform/FloatConversion.h"
25 #include "platform/geometry/FloatSize.h"
26 #include "wtf/MathExtras.h"
27 #include "wtf/text/StringBuilder.h"
28
29 namespace WebCore {
30
SVGTransform()31 SVGTransform::SVGTransform()
32 : m_type(SVG_TRANSFORM_UNKNOWN)
33 , m_angle(0)
34 {
35 }
36
SVGTransform(SVGTransformType type,ConstructionMode mode)37 SVGTransform::SVGTransform(SVGTransformType type, ConstructionMode mode)
38 : m_type(type)
39 , m_angle(0)
40 {
41 if (mode == ConstructZeroTransform)
42 m_matrix = AffineTransform(0, 0, 0, 0, 0, 0);
43 }
44
SVGTransform(const AffineTransform & matrix)45 SVGTransform::SVGTransform(const AffineTransform& matrix)
46 : m_type(SVG_TRANSFORM_MATRIX)
47 , m_angle(0)
48 , m_matrix(matrix)
49 {
50 }
51
setMatrix(const AffineTransform & matrix)52 void SVGTransform::setMatrix(const AffineTransform& matrix)
53 {
54 m_type = SVG_TRANSFORM_MATRIX;
55 m_angle = 0;
56 m_matrix = matrix;
57 }
58
updateSVGMatrix()59 void SVGTransform::updateSVGMatrix()
60 {
61 // The underlying matrix has been changed, alter the transformation type.
62 // Spec: In case the matrix object is changed directly (i.e., without using the methods on the SVGTransform interface itself)
63 // then the type of the SVGTransform changes to SVG_TRANSFORM_MATRIX.
64 m_type = SVG_TRANSFORM_MATRIX;
65 m_angle = 0;
66 }
67
setTranslate(float tx,float ty)68 void SVGTransform::setTranslate(float tx, float ty)
69 {
70 m_type = SVG_TRANSFORM_TRANSLATE;
71 m_angle = 0;
72
73 m_matrix.makeIdentity();
74 m_matrix.translate(tx, ty);
75 }
76
translate() const77 FloatPoint SVGTransform::translate() const
78 {
79 return FloatPoint::narrowPrecision(m_matrix.e(), m_matrix.f());
80 }
81
setScale(float sx,float sy)82 void SVGTransform::setScale(float sx, float sy)
83 {
84 m_type = SVG_TRANSFORM_SCALE;
85 m_angle = 0;
86 m_center = FloatPoint();
87
88 m_matrix.makeIdentity();
89 m_matrix.scaleNonUniform(sx, sy);
90 }
91
scale() const92 FloatSize SVGTransform::scale() const
93 {
94 return FloatSize::narrowPrecision(m_matrix.a(), m_matrix.d());
95 }
96
setRotate(float angle,float cx,float cy)97 void SVGTransform::setRotate(float angle, float cx, float cy)
98 {
99 m_type = SVG_TRANSFORM_ROTATE;
100 m_angle = angle;
101 m_center = FloatPoint(cx, cy);
102
103 // TODO: toString() implementation, which can show cx, cy (need to be stored?)
104 m_matrix.makeIdentity();
105 m_matrix.translate(cx, cy);
106 m_matrix.rotate(angle);
107 m_matrix.translate(-cx, -cy);
108 }
109
setSkewX(float angle)110 void SVGTransform::setSkewX(float angle)
111 {
112 m_type = SVG_TRANSFORM_SKEWX;
113 m_angle = angle;
114
115 m_matrix.makeIdentity();
116 m_matrix.skewX(angle);
117 }
118
setSkewY(float angle)119 void SVGTransform::setSkewY(float angle)
120 {
121 m_type = SVG_TRANSFORM_SKEWY;
122 m_angle = angle;
123
124 m_matrix.makeIdentity();
125 m_matrix.skewY(angle);
126 }
127
transformTypePrefixForParsing(SVGTransformType type)128 const String& SVGTransform::transformTypePrefixForParsing(SVGTransformType type)
129 {
130 switch (type) {
131 case SVG_TRANSFORM_UNKNOWN:
132 return emptyString();
133 case SVG_TRANSFORM_MATRIX: {
134 DEFINE_STATIC_LOCAL(String, matrixString, ("matrix("));
135 return matrixString;
136 }
137 case SVG_TRANSFORM_TRANSLATE: {
138 DEFINE_STATIC_LOCAL(String, translateString, ("translate("));
139 return translateString;
140 }
141 case SVG_TRANSFORM_SCALE: {
142 DEFINE_STATIC_LOCAL(String, scaleString, ("scale("));
143 return scaleString;
144 }
145 case SVG_TRANSFORM_ROTATE: {
146 DEFINE_STATIC_LOCAL(String, rotateString, ("rotate("));
147 return rotateString;
148 }
149 case SVG_TRANSFORM_SKEWX: {
150 DEFINE_STATIC_LOCAL(String, skewXString, ("skewX("));
151 return skewXString;
152 }
153 case SVG_TRANSFORM_SKEWY: {
154 DEFINE_STATIC_LOCAL(String, skewYString, ("skewY("));
155 return skewYString;
156 }
157 }
158
159 ASSERT_NOT_REACHED();
160 return emptyString();
161 }
162
valueAsString() const163 String SVGTransform::valueAsString() const
164 {
165 const String& prefix = transformTypePrefixForParsing(m_type);
166 switch (m_type) {
167 case SVG_TRANSFORM_UNKNOWN:
168 return prefix;
169 case SVG_TRANSFORM_MATRIX: {
170 StringBuilder builder;
171 builder.append(prefix + String::number(m_matrix.a()) + ' ' + String::number(m_matrix.b()) + ' ' + String::number(m_matrix.c()) + ' ' +
172 String::number(m_matrix.d()) + ' ' + String::number(m_matrix.e()) + ' ' + String::number(m_matrix.f()) + ')');
173 return builder.toString();
174 }
175 case SVG_TRANSFORM_TRANSLATE:
176 return prefix + String::number(m_matrix.e()) + ' ' + String::number(m_matrix.f()) + ')';
177 case SVG_TRANSFORM_SCALE:
178 return prefix + String::number(m_matrix.xScale()) + ' ' + String::number(m_matrix.yScale()) + ')';
179 case SVG_TRANSFORM_ROTATE: {
180 double angleInRad = deg2rad(m_angle);
181 double cosAngle = cos(angleInRad);
182 double sinAngle = sin(angleInRad);
183 float cx = narrowPrecisionToFloat(cosAngle != 1 ? (m_matrix.e() * (1 - cosAngle) - m_matrix.f() * sinAngle) / (1 - cosAngle) / 2 : 0);
184 float cy = narrowPrecisionToFloat(cosAngle != 1 ? (m_matrix.e() * sinAngle / (1 - cosAngle) + m_matrix.f()) / 2 : 0);
185 if (cx || cy)
186 return prefix + String::number(m_angle) + ' ' + String::number(cx) + ' ' + String::number(cy) + ')';
187 return prefix + String::number(m_angle) + ')';
188 }
189 case SVG_TRANSFORM_SKEWX:
190 return prefix + String::number(m_angle) + ')';
191 case SVG_TRANSFORM_SKEWY:
192 return prefix + String::number(m_angle) + ')';
193 }
194
195 ASSERT_NOT_REACHED();
196 return emptyString();
197 }
198
199 } // namespace WebCore
200