File indexing completed on 2024-04-28 15:24:42

0001 /*
0002  Copyright (C) 2007 Eric Seidel <eric@webkit.org>
0003 
0004  This file is part of the WebKit project
0005 
0006  This library is free software; you can redistribute it and/or
0007  modify it under the terms of the GNU Library General Public
0008  License as published by the Free Software Foundation; either
0009  version 2 of the License, or (at your option) any later version.
0010 
0011  This library is distributed in the hope that it will be useful,
0012  but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  Library General Public License for more details.
0015 
0016  You should have received a copy of the GNU Library General Public License
0017  along with this library; see the file COPYING.LIB.  If not, write to
0018  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  Boston, MA 02110-1301, USA.
0020  */
0021 
0022 #include "wtf/Platform.h"
0023 #if ENABLE(SVG)
0024 #include "SVGTransformDistance.h"
0025 
0026 #include "FloatConversion.h"
0027 #include "FloatPoint.h"
0028 #include "FloatSize.h"
0029 
0030 #include <math.h>
0031 
0032 namespace WebCore
0033 {
0034 
0035 SVGTransformDistance::SVGTransformDistance()
0036     : m_type(SVGTransform::SVG_TRANSFORM_UNKNOWN)
0037     , m_angle(0)
0038 {
0039 }
0040 
0041 SVGTransformDistance::SVGTransformDistance(SVGTransform::SVGTransformType type, float angle, float cx, float cy, const AffineTransform &transform)
0042     : m_type(type)
0043     , m_angle(angle)
0044     , m_cx(cx)
0045     , m_cy(cy)
0046     , m_transform(transform)
0047 {
0048 }
0049 
0050 SVGTransformDistance::SVGTransformDistance(const SVGTransform &fromSVGTransform, const SVGTransform &toSVGTransform)
0051     : m_type(fromSVGTransform.type())
0052     , m_angle(0)
0053     , m_cx(0)
0054     , m_cy(0)
0055 {
0056     ASSERT(m_type == toSVGTransform.type());
0057 
0058     switch (m_type) {
0059     case SVGTransform::SVG_TRANSFORM_UNKNOWN:
0060         return;
0061     case SVGTransform::SVG_TRANSFORM_MATRIX:
0062         // FIXME: need to be able to subtract to matrices
0063         return;
0064     case SVGTransform::SVG_TRANSFORM_ROTATE: {
0065         FloatSize centerDistance = toSVGTransform.rotationCenter() - fromSVGTransform.rotationCenter();
0066         m_angle = toSVGTransform.angle() - fromSVGTransform.angle();
0067         m_cx = centerDistance.width();
0068         m_cy = centerDistance.height();
0069         return;
0070     }
0071     case SVGTransform::SVG_TRANSFORM_TRANSLATE: {
0072         FloatSize translationDistance = toSVGTransform.translate() - fromSVGTransform.translate();
0073         m_transform.translate(translationDistance.width(), translationDistance.height());
0074         return;
0075     }
0076     case SVGTransform::SVG_TRANSFORM_SCALE: {
0077         float scaleX = toSVGTransform.scale().width() - fromSVGTransform.scale().width();
0078         float scaleY = toSVGTransform.scale().height() - fromSVGTransform.scale().height();
0079         m_transform.scale(scaleX, scaleY);
0080         return;
0081     }
0082     case SVGTransform::SVG_TRANSFORM_SKEWX:
0083     case SVGTransform::SVG_TRANSFORM_SKEWY:
0084         m_angle = toSVGTransform.angle() - fromSVGTransform.angle();
0085         return;
0086     }
0087 }
0088 
0089 SVGTransformDistance SVGTransformDistance::scaledDistance(float scaleFactor) const
0090 {
0091     switch (m_type) {
0092     case SVGTransform::SVG_TRANSFORM_UNKNOWN:
0093         return SVGTransformDistance();
0094     case SVGTransform::SVG_TRANSFORM_ROTATE:
0095         return SVGTransformDistance(m_type, m_angle * scaleFactor, m_cx * scaleFactor, m_cy * scaleFactor, AffineTransform());
0096     case SVGTransform::SVG_TRANSFORM_SCALE:
0097     case SVGTransform::SVG_TRANSFORM_MATRIX:
0098         return SVGTransformDistance(m_type, m_angle * scaleFactor, m_cx * scaleFactor, m_cy * scaleFactor, AffineTransform(m_transform).scale(scaleFactor));
0099     case SVGTransform::SVG_TRANSFORM_TRANSLATE: {
0100         AffineTransform newTransform(m_transform);
0101         newTransform.setE(m_transform.e() * scaleFactor);
0102         newTransform.setF(m_transform.f() * scaleFactor);
0103         return SVGTransformDistance(m_type, 0, 0, 0, newTransform);
0104     }
0105     case SVGTransform::SVG_TRANSFORM_SKEWX:
0106     case SVGTransform::SVG_TRANSFORM_SKEWY:
0107         return SVGTransformDistance(m_type, m_angle * scaleFactor, m_cx * scaleFactor, m_cy * scaleFactor, AffineTransform());
0108     }
0109 
0110     ASSERT_NOT_REACHED();
0111     return SVGTransformDistance();
0112 }
0113 
0114 SVGTransform SVGTransformDistance::addSVGTransforms(const SVGTransform &first, const SVGTransform &second)
0115 {
0116     ASSERT(first.type() == second.type());
0117 
0118     SVGTransform transform;
0119 
0120     switch (first.type()) {
0121     case SVGTransform::SVG_TRANSFORM_UNKNOWN:
0122         return SVGTransform();
0123     case SVGTransform::SVG_TRANSFORM_ROTATE: {
0124         transform.setRotate(first.angle() + second.angle(), first.rotationCenter().x() + second.rotationCenter().x(),
0125                             first.rotationCenter().y() + second.rotationCenter().y());
0126         return transform;
0127     }
0128     case SVGTransform::SVG_TRANSFORM_MATRIX:
0129         transform.setMatrix(first.matrix() * second.matrix());
0130         return transform;
0131     case SVGTransform::SVG_TRANSFORM_TRANSLATE: {
0132         float dx = first.translate().x() + second.translate().x();
0133         float dy = first.translate().y() + second.translate().y();
0134         transform.setTranslate(dx, dy);
0135         return transform;
0136     }
0137     case SVGTransform::SVG_TRANSFORM_SCALE: {
0138         FloatSize scale = first.scale() + second.scale();
0139         transform.setScale(scale.width(), scale.height());
0140         return transform;
0141     }
0142     case SVGTransform::SVG_TRANSFORM_SKEWX:
0143         transform.setSkewX(first.angle() + second.angle());
0144         return transform;
0145     case SVGTransform::SVG_TRANSFORM_SKEWY:
0146         transform.setSkewY(first.angle() + second.angle());
0147         return transform;
0148     }
0149 
0150     ASSERT_NOT_REACHED();
0151     return SVGTransform();
0152 }
0153 
0154 void SVGTransformDistance::addSVGTransform(const SVGTransform &transform, bool absoluteValue)
0155 {
0156     // If this is the first add, set the type for this SVGTransformDistance
0157     if (m_type == SVGTransform::SVG_TRANSFORM_UNKNOWN) {
0158         m_type = transform.type();
0159     }
0160 
0161     ASSERT(m_type == transform.type());
0162 
0163     switch (m_type) {
0164     case SVGTransform::SVG_TRANSFORM_UNKNOWN:
0165         return;
0166     case SVGTransform::SVG_TRANSFORM_MATRIX:
0167         m_transform *= transform.matrix(); // FIXME: what does 'distance' between two transforms mean?  how should we respect 'absoluteValue' here?
0168         return;
0169     case SVGTransform::SVG_TRANSFORM_ROTATE:
0170         m_angle += absoluteValue ? fabsf(transform.angle()) : transform.angle();
0171         m_cx += absoluteValue ? fabsf(transform.rotationCenter().x()) : transform.rotationCenter().x();
0172         m_cy += absoluteValue ? fabsf(transform.rotationCenter().y()) : transform.rotationCenter().y();
0173     // fall through
0174     case SVGTransform::SVG_TRANSFORM_TRANSLATE: {
0175         float dx = absoluteValue ? fabsf(transform.translate().x()) : transform.translate().x();
0176         float dy = absoluteValue ? fabsf(transform.translate().y()) : transform.translate().y();
0177         m_transform.translate(dx, dy);
0178         return;
0179     }
0180     case SVGTransform::SVG_TRANSFORM_SCALE: {
0181         float scaleX = absoluteValue ? fabsf(transform.scale().width()) : transform.scale().width();
0182         float scaleY = absoluteValue ? fabsf(transform.scale().height()) : transform.scale().height();
0183         m_transform.scale(scaleX, scaleY);
0184         return;
0185     }
0186     case SVGTransform::SVG_TRANSFORM_SKEWX:
0187     case SVGTransform::SVG_TRANSFORM_SKEWY:
0188         m_angle += absoluteValue ? fabsf(transform.angle()) : transform.angle();
0189         return;
0190     }
0191 
0192     ASSERT_NOT_REACHED();
0193     return;
0194 }
0195 
0196 SVGTransform SVGTransformDistance::addToSVGTransform(const SVGTransform &transform) const
0197 {
0198     ASSERT(m_type == transform.type() || transform == SVGTransform());
0199 
0200     SVGTransform newTransform(transform);
0201 
0202     switch (m_type) {
0203     case SVGTransform::SVG_TRANSFORM_UNKNOWN:
0204         return SVGTransform();
0205     case SVGTransform::SVG_TRANSFORM_MATRIX:
0206         return SVGTransform(transform.matrix() * m_transform);
0207     case SVGTransform::SVG_TRANSFORM_TRANSLATE: {
0208         FloatPoint translation = transform.translate();
0209         translation += FloatSize::narrowPrecision(m_transform.e(), m_transform.f());
0210         newTransform.setTranslate(translation.x(), translation.y());
0211         return newTransform;
0212     }
0213     case SVGTransform::SVG_TRANSFORM_SCALE: {
0214         FloatSize scale = transform.scale();
0215         scale += FloatSize::narrowPrecision(m_transform.a(), m_transform.d());
0216         newTransform.setScale(scale.width(), scale.height());
0217         return newTransform;
0218     }
0219     case SVGTransform::SVG_TRANSFORM_ROTATE: {
0220         // FIXME: I'm not certain the translation is calculated correctly here
0221         FloatPoint center = transform.rotationCenter();
0222         newTransform.setRotate(transform.angle() + m_angle,
0223                                center.x() + m_cx,
0224                                center.y() + m_cy);
0225         return newTransform;
0226     }
0227     case SVGTransform::SVG_TRANSFORM_SKEWX:
0228         newTransform.setSkewX(transform.angle() + m_angle);
0229         return newTransform;
0230     case SVGTransform::SVG_TRANSFORM_SKEWY:
0231         newTransform.setSkewY(transform.angle() + m_angle);
0232         return newTransform;
0233     }
0234 
0235     ASSERT_NOT_REACHED();
0236     return SVGTransform();
0237 }
0238 
0239 bool SVGTransformDistance::isZero() const
0240 {
0241     return (m_transform == AffineTransform() && m_angle == 0);
0242 }
0243 
0244 float SVGTransformDistance::distance() const
0245 {
0246     switch (m_type) {
0247     case SVGTransform::SVG_TRANSFORM_UNKNOWN:
0248         return 0.0f;
0249     case SVGTransform::SVG_TRANSFORM_ROTATE:
0250         return sqrtf(m_angle * m_angle + m_cx * m_cx + m_cy * m_cy);
0251     case SVGTransform::SVG_TRANSFORM_MATRIX:
0252         return 0.0f; // I'm not quite sure yet what distance between two matrices means.
0253     case SVGTransform::SVG_TRANSFORM_SCALE:
0254         return static_cast<float>(sqrt(m_transform.a() * m_transform.a() + m_transform.d() * m_transform.d()));
0255     case SVGTransform::SVG_TRANSFORM_TRANSLATE:
0256         return static_cast<float>(sqrt(m_transform.e() * m_transform.e() + m_transform.f() * m_transform.f()));
0257     case SVGTransform::SVG_TRANSFORM_SKEWX:
0258     case SVGTransform::SVG_TRANSFORM_SKEWY:
0259         return m_angle;
0260     }
0261     ASSERT_NOT_REACHED();
0262     return 0.0f;
0263 }
0264 
0265 }
0266 
0267 #endif