Home | History | Annotate | Download | only in svg
      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