File indexing completed on 2024-04-28 15:24:28

0001 /*
0002     Copyright (C) 2004, 2005 Nikolas Zimmermann <wildfox@kde.org>
0003                   2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
0004     Copyright (C) 2007 Eric Seidel <eric@webkit.org>
0005     Copyright (C) 2008 Apple Inc. All Rights Reserved.
0006 
0007     This file is part of the WebKit project
0008 
0009     This library is free software; you can redistribute it and/or
0010     modify it under the terms of the GNU Library General Public
0011     License as published by the Free Software Foundation; either
0012     version 2 of the License, or (at your option) any later version.
0013 
0014     This library is distributed in the hope that it will be useful,
0015     but WITHOUT ANY WARRANTY; without even the implied warranty of
0016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0017     Library General Public License for more details.
0018 
0019     You should have received a copy of the GNU Library General Public License
0020     along with this library; see the file COPYING.LIB.  If not, write to
0021     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0022     Boston, MA 02110-1301, USA.
0023 */
0024 
0025 #if ENABLE(SVG) && ENABLE(SVG_ANIMATION)
0026 #include "SVGAnimateTransformElement.h"
0027 
0028 #include "AffineTransform.h"
0029 #include "RenderObject.h"
0030 #include "SVGAngle.h"
0031 #include "SVGElementInstance.h"
0032 #include "SVGParserUtilities.h"
0033 #include "SVGSVGElement.h"
0034 #include "SVGStyledTransformableElement.h"
0035 #include "SVGTextElement.h"
0036 #include "SVGTransformList.h"
0037 #include "SVGUseElement.h"
0038 
0039 #include <math.h>
0040 #include <wtf/MathExtras.h>
0041 
0042 using namespace std;
0043 
0044 namespace WebCore
0045 {
0046 
0047 SVGAnimateTransformElement::SVGAnimateTransformElement(const QualifiedName &tagName, Document *doc)
0048     : SVGAnimationElement(tagName, doc)
0049     , m_type(SVGTransform::SVG_TRANSFORM_UNKNOWN)
0050     , m_baseIndexInTransformList(0)
0051 {
0052 }
0053 
0054 SVGAnimateTransformElement::~SVGAnimateTransformElement()
0055 {
0056 }
0057 
0058 bool SVGAnimateTransformElement::hasValidTarget() const
0059 {
0060     SVGElement *targetElement = this->targetElement();
0061     return SVGAnimationElement::hasValidTarget() && (targetElement->isStyledTransformable() || targetElement->hasTagName(SVGNames::textTag));
0062 }
0063 
0064 void SVGAnimateTransformElement::parseMappedAttribute(MappedAttribute *attr)
0065 {
0066     if (attr->name() == SVGNames::typeAttr) {
0067         if (attr->value() == "translate") {
0068             m_type = SVGTransform::SVG_TRANSFORM_TRANSLATE;
0069         } else if (attr->value() == "scale") {
0070             m_type = SVGTransform::SVG_TRANSFORM_SCALE;
0071         } else if (attr->value() == "rotate") {
0072             m_type = SVGTransform::SVG_TRANSFORM_ROTATE;
0073         } else if (attr->value() == "skewX") {
0074             m_type = SVGTransform::SVG_TRANSFORM_SKEWX;
0075         } else if (attr->value() == "skewY") {
0076             m_type = SVGTransform::SVG_TRANSFORM_SKEWY;
0077         }
0078     } else {
0079         SVGAnimationElement::parseMappedAttribute(attr);
0080     }
0081 }
0082 
0083 static PassRefPtr<SVGTransformList> transformListFor(SVGElement *element)
0084 {
0085     ASSERT(element);
0086     if (element->isStyledTransformable()) {
0087         return static_cast<SVGStyledTransformableElement *>(element)->transform();
0088     }
0089     if (element->hasTagName(SVGNames::textTag)) {
0090         return static_cast<SVGTextElement *>(element)->transform();
0091     }
0092     return 0;
0093 }
0094 
0095 void SVGAnimateTransformElement::resetToBaseValue(const String &baseValue)
0096 {
0097     if (!hasValidTarget()) {
0098         return;
0099     }
0100     if (baseValue.isEmpty()) {
0101         ExceptionCode ec;
0102         RefPtr<SVGTransformList> list = transformListFor(targetElement());
0103         list->clear(ec);
0104     } else {
0105         targetElement()->setAttribute(SVGNames::transformAttr, baseValue);
0106     }
0107 }
0108 
0109 void SVGAnimateTransformElement::calculateAnimatedValue(float percentage, unsigned repeat, SVGSMILElement *resultElement)
0110 {
0111     if (!hasValidTarget()) {
0112         return;
0113     }
0114     SVGElement *targetElement = resultElement->targetElement();
0115     RefPtr<SVGTransformList> transformList = transformListFor(targetElement);
0116     ASSERT(transformList);
0117 
0118     ExceptionCode ec;
0119     if (!isAdditive()) {
0120         transformList->clear(ec);
0121     }
0122     if (isAccumulated() && repeat) {
0123         SVGTransform accumulatedTransform = SVGTransformDistance(m_fromTransform, m_toTransform).scaledDistance(repeat).addToSVGTransform(SVGTransform());
0124         transformList->appendItem(accumulatedTransform, ec);
0125     }
0126     SVGTransform transform = SVGTransformDistance(m_fromTransform, m_toTransform).scaledDistance(percentage).addToSVGTransform(m_fromTransform);
0127     transformList->appendItem(transform, ec);
0128 }
0129 
0130 bool SVGAnimateTransformElement::calculateFromAndToValues(const String &fromString, const String &toString)
0131 {
0132     m_fromTransform = parseTransformValue(fromString);
0133     if (!m_fromTransform.isValid()) {
0134         return false;
0135     }
0136     m_toTransform = parseTransformValue(toString);
0137     return m_toTransform.isValid();
0138 }
0139 
0140 bool SVGAnimateTransformElement::calculateFromAndByValues(const String &fromString, const String &byString)
0141 {
0142 
0143     m_fromTransform = parseTransformValue(fromString);
0144     if (!m_fromTransform.isValid()) {
0145         return false;
0146     }
0147     m_toTransform = SVGTransformDistance::addSVGTransforms(m_fromTransform, parseTransformValue(byString));
0148     return m_toTransform.isValid();
0149 }
0150 
0151 SVGTransform SVGAnimateTransformElement::parseTransformValue(const String &value) const
0152 {
0153     if (value.isEmpty()) {
0154         return SVGTransform(m_type);
0155     }
0156     SVGTransform result;
0157     // FIXME: This is pretty dumb but parseTransformValue() wants those parenthesis.
0158     String parseString("(" + value + ")");
0159     const UChar *ptr = parseString.characters();
0160     SVGTransformable::parseTransformValue(m_type, ptr, ptr + parseString.length(), result); // ignoring return value
0161     return result;
0162 }
0163 
0164 void SVGAnimateTransformElement::applyResultsToTarget()
0165 {
0166     if (!hasValidTarget()) {
0167         return;
0168     }
0169     // We accumulate to the target element transform list so there is not much to do here.
0170     SVGElement *targetElement = this->targetElement();
0171     if (targetElement->renderer()) {
0172         targetElement->renderer()->setNeedsLayout(true);
0173     }
0174 
0175     // ...except in case where we have additional instances in <use> trees.
0176     HashSet<SVGElementInstance *> *instances = document()->accessSVGExtensions()->instancesForElement(targetElement);
0177     if (!instances) {
0178         return;
0179     }
0180     RefPtr<SVGTransformList> transformList = transformListFor(targetElement);
0181     HashSet<SVGElementInstance *>::iterator end = instances->end();
0182     for (HashSet<SVGElementInstance *>::iterator it = instances->begin(); it != end; ++it) {
0183         SVGElement *shadowTreeElement = (*it)->shadowTreeElement();
0184         ASSERT(shadowTreeElement);
0185         if (shadowTreeElement->isStyledTransformable()) {
0186             static_cast<SVGStyledTransformableElement *>(shadowTreeElement)->setTransform(transformList.get());
0187         } else if (shadowTreeElement->hasTagName(SVGNames::textTag)) {
0188             static_cast<SVGTextElement *>(shadowTreeElement)->setTransform(transformList.get());
0189         }
0190         if (shadowTreeElement->renderer()) {
0191             shadowTreeElement->renderer()->setNeedsLayout(true);
0192         }
0193     }
0194 }
0195 
0196 float SVGAnimateTransformElement::calculateDistance(const String &fromString, const String &toString)
0197 {
0198     // FIXME: This is not correct in all cases. The spec demands that each component (translate x and y for example)
0199     // is paced separately. To implement this we need to treat each component as individual animation everywhere.
0200     SVGTransform from = parseTransformValue(fromString);
0201     if (!from.isValid()) {
0202         return -1.f;
0203     }
0204     SVGTransform to = parseTransformValue(toString);
0205     if (!to.isValid() || from.type() != to.type()) {
0206         return -1.f;
0207     }
0208     if (to.type() == SVGTransform::SVG_TRANSFORM_TRANSLATE) {
0209         FloatSize diff = to.translate() - from.translate();
0210         return sqrtf(diff.width() * diff.width() + diff.height() * diff.height());
0211     }
0212     if (to.type() == SVGTransform::SVG_TRANSFORM_ROTATE) {
0213         return fabsf(to.angle() - from.angle());
0214     }
0215     if (to.type() == SVGTransform::SVG_TRANSFORM_SCALE) {
0216         FloatSize diff = to.scale() - from.scale();
0217         return sqrtf(diff.width() * diff.width() + diff.height() * diff.height());
0218     }
0219     return -1.f;
0220 }
0221 
0222 }
0223 
0224 #endif // ENABLE(SVG)
0225