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