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 : m_type(SVG_TRANSFORM_UNKNOWN) 33 , m_angle(0) 34 { 35 } 36 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 45 SVGTransform::SVGTransform(const AffineTransform& matrix) 46 : m_type(SVG_TRANSFORM_MATRIX) 47 , m_angle(0) 48 , m_matrix(matrix) 49 { 50 } 51 52 void SVGTransform::setMatrix(const AffineTransform& matrix) 53 { 54 m_type = SVG_TRANSFORM_MATRIX; 55 m_angle = 0; 56 m_matrix = matrix; 57 } 58 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 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 77 FloatPoint SVGTransform::translate() const 78 { 79 return FloatPoint::narrowPrecision(m_matrix.e(), m_matrix.f()); 80 } 81 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 92 FloatSize SVGTransform::scale() const 93 { 94 return FloatSize::narrowPrecision(m_matrix.a(), m_matrix.d()); 95 } 96 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 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 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 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 163 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