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