1 /* 2 * Copyright (C) 2004, 2005 Nikolas Zimmermann <zimmermann (at) kde.org> 3 * Copyright (C) 2004, 2005 Rob Buis <buis (at) 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 31 SVGTransform::SVGTransform() 32 : SVGPropertyBase(classType()) 33 , m_transformType(SVG_TRANSFORM_UNKNOWN) 34 , m_angle(0) 35 { 36 } 37 38 SVGTransform::SVGTransform(SVGTransformType transformType, ConstructionMode mode) 39 : SVGPropertyBase(classType()) 40 , m_transformType(transformType) 41 , m_angle(0) 42 { 43 if (mode == ConstructZeroTransform) 44 m_matrix = AffineTransform(0, 0, 0, 0, 0, 0); 45 } 46 47 SVGTransform::SVGTransform(const AffineTransform& matrix) 48 : SVGPropertyBase(classType()) 49 , m_transformType(SVG_TRANSFORM_MATRIX) 50 , m_angle(0) 51 , m_matrix(matrix) 52 { 53 } 54 55 SVGTransform::SVGTransform(SVGTransformType transformType, float angle, const FloatPoint& center, const AffineTransform& matrix) 56 : SVGPropertyBase(classType()) 57 , m_transformType(transformType) 58 , m_angle(angle) 59 , m_center(center) 60 , m_matrix(matrix) 61 { 62 } 63 64 SVGTransform::~SVGTransform() 65 { 66 } 67 68 PassRefPtr<SVGTransform> SVGTransform::clone() const 69 { 70 return adoptRef(new SVGTransform(m_transformType, m_angle, m_center, m_matrix)); 71 } 72 73 PassRefPtr<SVGPropertyBase> SVGTransform::cloneForAnimation(const String&) const 74 { 75 // SVGTransform is never animated. 76 ASSERT_NOT_REACHED(); 77 return nullptr; 78 } 79 80 void SVGTransform::setMatrix(const AffineTransform& matrix) 81 { 82 onMatrixChange(); 83 m_matrix = matrix; 84 } 85 86 void SVGTransform::onMatrixChange() 87 { 88 m_transformType = SVG_TRANSFORM_MATRIX; 89 m_angle = 0; 90 } 91 92 void SVGTransform::setTranslate(float tx, float ty) 93 { 94 m_transformType = SVG_TRANSFORM_TRANSLATE; 95 m_angle = 0; 96 97 m_matrix.makeIdentity(); 98 m_matrix.translate(tx, ty); 99 } 100 101 FloatPoint SVGTransform::translate() const 102 { 103 return FloatPoint::narrowPrecision(m_matrix.e(), m_matrix.f()); 104 } 105 106 void SVGTransform::setScale(float sx, float sy) 107 { 108 m_transformType = SVG_TRANSFORM_SCALE; 109 m_angle = 0; 110 m_center = FloatPoint(); 111 112 m_matrix.makeIdentity(); 113 m_matrix.scaleNonUniform(sx, sy); 114 } 115 116 FloatSize SVGTransform::scale() const 117 { 118 return FloatSize::narrowPrecision(m_matrix.a(), m_matrix.d()); 119 } 120 121 void SVGTransform::setRotate(float angle, float cx, float cy) 122 { 123 m_transformType = SVG_TRANSFORM_ROTATE; 124 m_angle = angle; 125 m_center = FloatPoint(cx, cy); 126 127 // TODO: toString() implementation, which can show cx, cy (need to be stored?) 128 m_matrix.makeIdentity(); 129 m_matrix.translate(cx, cy); 130 m_matrix.rotate(angle); 131 m_matrix.translate(-cx, -cy); 132 } 133 134 void SVGTransform::setSkewX(float angle) 135 { 136 m_transformType = SVG_TRANSFORM_SKEWX; 137 m_angle = angle; 138 139 m_matrix.makeIdentity(); 140 m_matrix.skewX(angle); 141 } 142 143 void SVGTransform::setSkewY(float angle) 144 { 145 m_transformType = SVG_TRANSFORM_SKEWY; 146 m_angle = angle; 147 148 m_matrix.makeIdentity(); 149 m_matrix.skewY(angle); 150 } 151 152 namespace { 153 154 const String& transformTypePrefixForParsing(SVGTransformType type) 155 { 156 switch (type) { 157 case SVG_TRANSFORM_UNKNOWN: 158 return emptyString(); 159 case SVG_TRANSFORM_MATRIX: { 160 DEFINE_STATIC_LOCAL(String, matrixString, ("matrix(")); 161 return matrixString; 162 } 163 case SVG_TRANSFORM_TRANSLATE: { 164 DEFINE_STATIC_LOCAL(String, translateString, ("translate(")); 165 return translateString; 166 } 167 case SVG_TRANSFORM_SCALE: { 168 DEFINE_STATIC_LOCAL(String, scaleString, ("scale(")); 169 return scaleString; 170 } 171 case SVG_TRANSFORM_ROTATE: { 172 DEFINE_STATIC_LOCAL(String, rotateString, ("rotate(")); 173 return rotateString; 174 } 175 case SVG_TRANSFORM_SKEWX: { 176 DEFINE_STATIC_LOCAL(String, skewXString, ("skewX(")); 177 return skewXString; 178 } 179 case SVG_TRANSFORM_SKEWY: { 180 DEFINE_STATIC_LOCAL(String, skewYString, ("skewY(")); 181 return skewYString; 182 } 183 } 184 185 ASSERT_NOT_REACHED(); 186 return emptyString(); 187 } 188 189 } 190 191 String SVGTransform::valueAsString() const 192 { 193 const String& prefix = transformTypePrefixForParsing(m_transformType); 194 switch (m_transformType) { 195 case SVG_TRANSFORM_UNKNOWN: 196 return prefix; 197 case SVG_TRANSFORM_MATRIX: { 198 StringBuilder builder; 199 builder.append(prefix + String::number(m_matrix.a()) + ' ' + String::number(m_matrix.b()) + ' ' + String::number(m_matrix.c()) + ' ' + 200 String::number(m_matrix.d()) + ' ' + String::number(m_matrix.e()) + ' ' + String::number(m_matrix.f()) + ')'); 201 return builder.toString(); 202 } 203 case SVG_TRANSFORM_TRANSLATE: 204 return prefix + String::number(m_matrix.e()) + ' ' + String::number(m_matrix.f()) + ')'; 205 case SVG_TRANSFORM_SCALE: 206 return prefix + String::number(m_matrix.xScale()) + ' ' + String::number(m_matrix.yScale()) + ')'; 207 case SVG_TRANSFORM_ROTATE: { 208 double angleInRad = deg2rad(m_angle); 209 double cosAngle = cos(angleInRad); 210 double sinAngle = sin(angleInRad); 211 float cx = narrowPrecisionToFloat(cosAngle != 1 ? (m_matrix.e() * (1 - cosAngle) - m_matrix.f() * sinAngle) / (1 - cosAngle) / 2 : 0); 212 float cy = narrowPrecisionToFloat(cosAngle != 1 ? (m_matrix.e() * sinAngle / (1 - cosAngle) + m_matrix.f()) / 2 : 0); 213 if (cx || cy) 214 return prefix + String::number(m_angle) + ' ' + String::number(cx) + ' ' + String::number(cy) + ')'; 215 return prefix + String::number(m_angle) + ')'; 216 } 217 case SVG_TRANSFORM_SKEWX: 218 return prefix + String::number(m_angle) + ')'; 219 case SVG_TRANSFORM_SKEWY: 220 return prefix + String::number(m_angle) + ')'; 221 } 222 223 ASSERT_NOT_REACHED(); 224 return emptyString(); 225 } 226 227 void SVGTransform::add(PassRefPtrWillBeRawPtr<SVGPropertyBase>, SVGElement*) 228 { 229 // SVGTransform is not animated by itself. 230 ASSERT_NOT_REACHED(); 231 } 232 233 void SVGTransform::calculateAnimatedValue(SVGAnimationElement*, float, unsigned, PassRefPtr<SVGPropertyBase>, PassRefPtr<SVGPropertyBase>, PassRefPtr<SVGPropertyBase>, SVGElement*) 234 { 235 // SVGTransform is not animated by itself. 236 ASSERT_NOT_REACHED(); 237 } 238 239 float SVGTransform::calculateDistance(PassRefPtr<SVGPropertyBase>, SVGElement*) 240 { 241 // SVGTransform is not animated by itself. 242 ASSERT_NOT_REACHED(); 243 244 return -1; 245 } 246 247 } // namespace WebCore 248