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 31namespace WebCore { 32 33SVGTransformDistance::SVGTransformDistance() 34 : m_type(SVGTransform::SVG_TRANSFORM_UNKNOWN) 35 , m_angle(0) 36 , m_cx(0) 37 , m_cy(0) 38{ 39} 40 41SVGTransformDistance::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 50SVGTransformDistance::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 89SVGTransformDistance 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 114SVGTransform 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 154void 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 195SVGTransform 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 238bool SVGTransformDistance::isZero() const 239{ 240 return m_transform.isIdentity() && !m_angle; 241} 242 243float 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