Home | History | Annotate | Download | only in svg
      1 /*
      2  * Copyright (C) 2007 Eric Seidel <eric (at) 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 
     31 namespace WebCore {
     32 
     33 SVGTransformDistance::SVGTransformDistance()
     34     : m_type(SVGTransform::SVG_TRANSFORM_UNKNOWN)
     35     , m_angle(0)
     36     , m_cx(0)
     37     , m_cy(0)
     38 {
     39 }
     40 
     41 SVGTransformDistance::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 
     50 SVGTransformDistance::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 
     89 SVGTransformDistance 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 
    114 SVGTransform 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 
    154 void 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 
    195 SVGTransform 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 
    238 bool SVGTransformDistance::isZero() const
    239 {
    240     return m_transform.isIdentity() && !m_angle;
    241 }
    242 
    243 float 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