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