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     : SVGPropertyBase(classType())
     33     , m_transformType(SVG_TRANSFORM_UNKNOWN)
     34     , m_angle(0)
     35 {
     36 }
     37 
     38 SVGTransform::SVGTransform(SVGTransformType transformType, ConstructionMode mode)
     39     : SVGPropertyBase(classType())
     40     , m_transformType(transformType)
     41     , m_angle(0)
     42 {
     43     if (mode == ConstructZeroTransform)
     44         m_matrix = AffineTransform(0, 0, 0, 0, 0, 0);
     45 }
     46 
     47 SVGTransform::SVGTransform(const AffineTransform& matrix)
     48     : SVGPropertyBase(classType())
     49     , m_transformType(SVG_TRANSFORM_MATRIX)
     50     , m_angle(0)
     51     , m_matrix(matrix)
     52 {
     53 }
     54 
     55 SVGTransform::SVGTransform(SVGTransformType transformType, float angle, const FloatPoint& center, const AffineTransform& matrix)
     56     : SVGPropertyBase(classType())
     57     , m_transformType(transformType)
     58     , m_angle(angle)
     59     , m_center(center)
     60     , m_matrix(matrix)
     61 {
     62 }
     63 
     64 SVGTransform::~SVGTransform()
     65 {
     66 }
     67 
     68 PassRefPtr<SVGTransform> SVGTransform::clone() const
     69 {
     70     return adoptRef(new SVGTransform(m_transformType, m_angle, m_center, m_matrix));
     71 }
     72 
     73 PassRefPtr<SVGPropertyBase> SVGTransform::cloneForAnimation(const String&) const
     74 {
     75     // SVGTransform is never animated.
     76     ASSERT_NOT_REACHED();
     77     return nullptr;
     78 }
     79 
     80 void SVGTransform::setMatrix(const AffineTransform& matrix)
     81 {
     82     onMatrixChange();
     83     m_matrix = matrix;
     84 }
     85 
     86 void SVGTransform::onMatrixChange()
     87 {
     88     m_transformType = SVG_TRANSFORM_MATRIX;
     89     m_angle = 0;
     90 }
     91 
     92 void SVGTransform::setTranslate(float tx, float ty)
     93 {
     94     m_transformType = SVG_TRANSFORM_TRANSLATE;
     95     m_angle = 0;
     96 
     97     m_matrix.makeIdentity();
     98     m_matrix.translate(tx, ty);
     99 }
    100 
    101 FloatPoint SVGTransform::translate() const
    102 {
    103     return FloatPoint::narrowPrecision(m_matrix.e(), m_matrix.f());
    104 }
    105 
    106 void SVGTransform::setScale(float sx, float sy)
    107 {
    108     m_transformType = SVG_TRANSFORM_SCALE;
    109     m_angle = 0;
    110     m_center = FloatPoint();
    111 
    112     m_matrix.makeIdentity();
    113     m_matrix.scaleNonUniform(sx, sy);
    114 }
    115 
    116 FloatSize SVGTransform::scale() const
    117 {
    118     return FloatSize::narrowPrecision(m_matrix.a(), m_matrix.d());
    119 }
    120 
    121 void SVGTransform::setRotate(float angle, float cx, float cy)
    122 {
    123     m_transformType = SVG_TRANSFORM_ROTATE;
    124     m_angle = angle;
    125     m_center = FloatPoint(cx, cy);
    126 
    127     // TODO: toString() implementation, which can show cx, cy (need to be stored?)
    128     m_matrix.makeIdentity();
    129     m_matrix.translate(cx, cy);
    130     m_matrix.rotate(angle);
    131     m_matrix.translate(-cx, -cy);
    132 }
    133 
    134 void SVGTransform::setSkewX(float angle)
    135 {
    136     m_transformType = SVG_TRANSFORM_SKEWX;
    137     m_angle = angle;
    138 
    139     m_matrix.makeIdentity();
    140     m_matrix.skewX(angle);
    141 }
    142 
    143 void SVGTransform::setSkewY(float angle)
    144 {
    145     m_transformType = SVG_TRANSFORM_SKEWY;
    146     m_angle = angle;
    147 
    148     m_matrix.makeIdentity();
    149     m_matrix.skewY(angle);
    150 }
    151 
    152 namespace {
    153 
    154 const String& transformTypePrefixForParsing(SVGTransformType type)
    155 {
    156     switch (type) {
    157     case SVG_TRANSFORM_UNKNOWN:
    158         return emptyString();
    159     case SVG_TRANSFORM_MATRIX: {
    160         DEFINE_STATIC_LOCAL(String, matrixString, ("matrix("));
    161         return matrixString;
    162     }
    163     case SVG_TRANSFORM_TRANSLATE: {
    164         DEFINE_STATIC_LOCAL(String, translateString, ("translate("));
    165         return translateString;
    166     }
    167     case SVG_TRANSFORM_SCALE: {
    168         DEFINE_STATIC_LOCAL(String, scaleString, ("scale("));
    169         return scaleString;
    170     }
    171     case SVG_TRANSFORM_ROTATE: {
    172         DEFINE_STATIC_LOCAL(String, rotateString, ("rotate("));
    173         return rotateString;
    174     }
    175     case SVG_TRANSFORM_SKEWX: {
    176         DEFINE_STATIC_LOCAL(String, skewXString, ("skewX("));
    177         return skewXString;
    178     }
    179     case SVG_TRANSFORM_SKEWY: {
    180         DEFINE_STATIC_LOCAL(String, skewYString, ("skewY("));
    181         return skewYString;
    182     }
    183     }
    184 
    185     ASSERT_NOT_REACHED();
    186     return emptyString();
    187 }
    188 
    189 }
    190 
    191 String SVGTransform::valueAsString() const
    192 {
    193     const String& prefix = transformTypePrefixForParsing(m_transformType);
    194     switch (m_transformType) {
    195     case SVG_TRANSFORM_UNKNOWN:
    196         return prefix;
    197     case SVG_TRANSFORM_MATRIX: {
    198         StringBuilder builder;
    199         builder.append(prefix + String::number(m_matrix.a()) + ' ' + String::number(m_matrix.b()) + ' ' + String::number(m_matrix.c()) + ' ' +
    200                        String::number(m_matrix.d()) + ' ' + String::number(m_matrix.e()) + ' ' + String::number(m_matrix.f()) + ')');
    201         return builder.toString();
    202     }
    203     case SVG_TRANSFORM_TRANSLATE:
    204         return prefix + String::number(m_matrix.e()) + ' ' + String::number(m_matrix.f()) + ')';
    205     case SVG_TRANSFORM_SCALE:
    206         return prefix + String::number(m_matrix.xScale()) + ' ' + String::number(m_matrix.yScale()) + ')';
    207     case SVG_TRANSFORM_ROTATE: {
    208         double angleInRad = deg2rad(m_angle);
    209         double cosAngle = cos(angleInRad);
    210         double sinAngle = sin(angleInRad);
    211         float cx = narrowPrecisionToFloat(cosAngle != 1 ? (m_matrix.e() * (1 - cosAngle) - m_matrix.f() * sinAngle) / (1 - cosAngle) / 2 : 0);
    212         float cy = narrowPrecisionToFloat(cosAngle != 1 ? (m_matrix.e() * sinAngle / (1 - cosAngle) + m_matrix.f()) / 2 : 0);
    213         if (cx || cy)
    214             return prefix + String::number(m_angle) + ' ' + String::number(cx) + ' ' + String::number(cy) + ')';
    215         return prefix + String::number(m_angle) + ')';
    216     }
    217     case SVG_TRANSFORM_SKEWX:
    218         return prefix + String::number(m_angle) + ')';
    219     case SVG_TRANSFORM_SKEWY:
    220         return prefix + String::number(m_angle) + ')';
    221     }
    222 
    223     ASSERT_NOT_REACHED();
    224     return emptyString();
    225 }
    226 
    227 void SVGTransform::add(PassRefPtrWillBeRawPtr<SVGPropertyBase>, SVGElement*)
    228 {
    229     // SVGTransform is not animated by itself.
    230     ASSERT_NOT_REACHED();
    231 }
    232 
    233 void SVGTransform::calculateAnimatedValue(SVGAnimationElement*, float, unsigned, PassRefPtr<SVGPropertyBase>, PassRefPtr<SVGPropertyBase>, PassRefPtr<SVGPropertyBase>, SVGElement*)
    234 {
    235     // SVGTransform is not animated by itself.
    236     ASSERT_NOT_REACHED();
    237 }
    238 
    239 float SVGTransform::calculateDistance(PassRefPtr<SVGPropertyBase>, SVGElement*)
    240 {
    241     // SVGTransform is not animated by itself.
    242     ASSERT_NOT_REACHED();
    243 
    244     return -1;
    245 }
    246 
    247 } // namespace WebCore
    248