Home | History | Annotate | Download | only in svg
      1 /*
      2     Copyright (C) 2004, 2005 Nikolas Zimmermann <wildfox (at) kde.org>
      3                   2004, 2005, 2006, 2007 Rob Buis <buis (at) kde.org>
      4     Copyright (C) 2007 Eric Seidel <eric (at) webkit.org>
      5     Copyright (C) 2008 Apple Inc. All Rights Reserved.
      6 
      7     This file is part of the WebKit project
      8 
      9     This library is free software; you can redistribute it and/or
     10     modify it under the terms of the GNU Library General Public
     11     License as published by the Free Software Foundation; either
     12     version 2 of the License, or (at your option) any later version.
     13 
     14     This library is distributed in the hope that it will be useful,
     15     but WITHOUT ANY WARRANTY; without even the implied warranty of
     16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     17     Library General Public License for more details.
     18 
     19     You should have received a copy of the GNU Library General Public License
     20     along with this library; see the file COPYING.LIB.  If not, write to
     21     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     22     Boston, MA 02110-1301, USA.
     23 */
     24 
     25 #include "config.h"
     26 
     27 #if ENABLE(SVG) && ENABLE(SVG_ANIMATION)
     28 #include "SVGAnimateTransformElement.h"
     29 
     30 #include "AffineTransform.h"
     31 #include "MappedAttribute.h"
     32 #include "RenderObject.h"
     33 #include "SVGAngle.h"
     34 #include "SVGElementInstance.h"
     35 #include "SVGParserUtilities.h"
     36 #include "SVGSVGElement.h"
     37 #include "SVGStyledTransformableElement.h"
     38 #include "SVGTextElement.h"
     39 #include "SVGTransform.h"
     40 #include "SVGTransformList.h"
     41 #include "SVGUseElement.h"
     42 #include <math.h>
     43 #include <wtf/MathExtras.h>
     44 
     45 using namespace std;
     46 
     47 namespace WebCore {
     48 
     49 SVGAnimateTransformElement::SVGAnimateTransformElement(const QualifiedName& tagName, Document* doc)
     50     : SVGAnimationElement(tagName, doc)
     51     , m_type(SVGTransform::SVG_TRANSFORM_UNKNOWN)
     52     , m_baseIndexInTransformList(0)
     53 {
     54 }
     55 
     56 SVGAnimateTransformElement::~SVGAnimateTransformElement()
     57 {
     58 }
     59 
     60 bool SVGAnimateTransformElement::hasValidTarget() const
     61 {
     62     SVGElement* targetElement = this->targetElement();
     63     return SVGAnimationElement::hasValidTarget() && (targetElement->isStyledTransformable() || targetElement->hasTagName(SVGNames::textTag));
     64 }
     65 
     66 void SVGAnimateTransformElement::parseMappedAttribute(MappedAttribute* attr)
     67 {
     68     if (attr->name() == SVGNames::typeAttr) {
     69         if (attr->value() == "translate")
     70             m_type = SVGTransform::SVG_TRANSFORM_TRANSLATE;
     71         else if (attr->value() == "scale")
     72             m_type = SVGTransform::SVG_TRANSFORM_SCALE;
     73         else if (attr->value() == "rotate")
     74             m_type = SVGTransform::SVG_TRANSFORM_ROTATE;
     75         else if (attr->value() == "skewX")
     76             m_type = SVGTransform::SVG_TRANSFORM_SKEWX;
     77         else if (attr->value() == "skewY")
     78             m_type = SVGTransform::SVG_TRANSFORM_SKEWY;
     79     } else
     80         SVGAnimationElement::parseMappedAttribute(attr);
     81 }
     82 
     83 
     84 static PassRefPtr<SVGTransformList> transformListFor(SVGElement* element)
     85 {
     86     ASSERT(element);
     87     if (element->isStyledTransformable())
     88         return static_cast<SVGStyledTransformableElement*>(element)->transform();
     89     if (element->hasTagName(SVGNames::textTag))
     90         return static_cast<SVGTextElement*>(element)->transform();
     91     return 0;
     92 }
     93 
     94 void SVGAnimateTransformElement::resetToBaseValue(const String& baseValue)
     95 {
     96     if (!hasValidTarget())
     97         return;
     98     if (baseValue.isEmpty()) {
     99         ExceptionCode ec;
    100         RefPtr<SVGTransformList> list = transformListFor(targetElement());
    101         list->clear(ec);
    102     } else
    103         targetElement()->setAttribute(SVGNames::transformAttr, baseValue);
    104 }
    105 
    106 void SVGAnimateTransformElement::calculateAnimatedValue(float percentage, unsigned repeat, SVGSMILElement* resultElement)
    107 {
    108     if (!hasValidTarget())
    109         return;
    110     SVGElement* targetElement = resultElement->targetElement();
    111     RefPtr<SVGTransformList> transformList = transformListFor(targetElement);
    112     ASSERT(transformList);
    113 
    114     ExceptionCode ec;
    115     if (!isAdditive())
    116         transformList->clear(ec);
    117     if (isAccumulated() && repeat) {
    118         SVGTransform accumulatedTransform = SVGTransformDistance(m_fromTransform, m_toTransform).scaledDistance(repeat).addToSVGTransform(SVGTransform());
    119         transformList->appendItem(accumulatedTransform, ec);
    120     }
    121     SVGTransform transform = SVGTransformDistance(m_fromTransform, m_toTransform).scaledDistance(percentage).addToSVGTransform(m_fromTransform);
    122     transformList->appendItem(transform, ec);
    123 }
    124 
    125 bool SVGAnimateTransformElement::calculateFromAndToValues(const String& fromString, const String& toString)
    126 {
    127     m_fromTransform = parseTransformValue(fromString);
    128     if (!m_fromTransform.isValid())
    129         return false;
    130     m_toTransform = parseTransformValue(toString);
    131     return m_toTransform.isValid();
    132 }
    133 
    134 bool SVGAnimateTransformElement::calculateFromAndByValues(const String& fromString, const String& byString)
    135 {
    136 
    137     m_fromTransform = parseTransformValue(fromString);
    138     if (!m_fromTransform.isValid())
    139         return false;
    140     m_toTransform = SVGTransformDistance::addSVGTransforms(m_fromTransform, parseTransformValue(byString));
    141     return m_toTransform.isValid();
    142 }
    143 
    144 SVGTransform SVGAnimateTransformElement::parseTransformValue(const String& value) const
    145 {
    146     if (value.isEmpty())
    147         return SVGTransform(m_type);
    148     SVGTransform result;
    149     // FIXME: This is pretty dumb but parseTransformValue() wants those parenthesis.
    150     String parseString("(" + value + ")");
    151     const UChar* ptr = parseString.characters();
    152     SVGTransformable::parseTransformValue(m_type, ptr, ptr + parseString.length(), result); // ignoring return value
    153     return result;
    154 }
    155 
    156 void SVGAnimateTransformElement::applyResultsToTarget()
    157 {
    158     if (!hasValidTarget())
    159         return;
    160     // We accumulate to the target element transform list so there is not much to do here.
    161     SVGElement* targetElement = this->targetElement();
    162     if (targetElement->renderer())
    163         targetElement->renderer()->setNeedsLayout(true);
    164 
    165     // ...except in case where we have additional instances in <use> trees.
    166     const HashSet<SVGElementInstance*>& instances = targetElement->instancesForElement();
    167     RefPtr<SVGTransformList> transformList = transformListFor(targetElement);
    168     const HashSet<SVGElementInstance*>::const_iterator end = instances.end();
    169     for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) {
    170         SVGElement* shadowTreeElement = (*it)->shadowTreeElement();
    171         ASSERT(shadowTreeElement);
    172         if (shadowTreeElement->isStyledTransformable())
    173             static_cast<SVGStyledTransformableElement*>(shadowTreeElement)->setTransformBaseValue(transformList.get());
    174         else if (shadowTreeElement->hasTagName(SVGNames::textTag))
    175             static_cast<SVGTextElement*>(shadowTreeElement)->setTransformBaseValue(transformList.get());
    176         if (shadowTreeElement->renderer())
    177             shadowTreeElement->renderer()->setNeedsLayout(true);
    178     }
    179 }
    180 
    181 float SVGAnimateTransformElement::calculateDistance(const String& fromString, const String& toString)
    182 {
    183     // FIXME: This is not correct in all cases. The spec demands that each component (translate x and y for example)
    184     // is paced separately. To implement this we need to treat each component as individual animation everywhere.
    185     SVGTransform from = parseTransformValue(fromString);
    186     if (!from.isValid())
    187         return -1.f;
    188     SVGTransform to = parseTransformValue(toString);
    189     if (!to.isValid() || from.type() != to.type())
    190         return -1.f;
    191     if (to.type() == SVGTransform::SVG_TRANSFORM_TRANSLATE) {
    192         FloatSize diff = to.translate() - from.translate();
    193         return sqrtf(diff.width() * diff.width() + diff.height() * diff.height());
    194     }
    195     if (to.type() == SVGTransform::SVG_TRANSFORM_ROTATE)
    196         return fabsf(to.angle() - from.angle());
    197     if (to.type() == SVGTransform::SVG_TRANSFORM_SCALE) {
    198         FloatSize diff = to.scale() - from.scale();
    199         return sqrtf(diff.width() * diff.width() + diff.height() * diff.height());
    200     }
    201     return -1.f;
    202 }
    203 
    204 }
    205 
    206 // vim:ts=4:noet
    207 #endif // ENABLE(SVG)
    208 
    209