KHTML
SVGAnimateTransformElement.cpp
Go to the documentation of this file.
00001 /* 00002 Copyright (C) 2004, 2005 Nikolas Zimmermann <wildfox@kde.org> 00003 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org> 00004 Copyright (C) 2007 Eric Seidel <eric@webkit.org> 00005 Copyright (C) 2008 Apple Inc. All Rights Reserved. 00006 00007 This file is part of the WebKit project 00008 00009 This library is free software; you can redistribute it and/or 00010 modify it under the terms of the GNU Library General Public 00011 License as published by the Free Software Foundation; either 00012 version 2 of the License, or (at your option) any later version. 00013 00014 This library is distributed in the hope that it will be useful, 00015 but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 Library General Public License for more details. 00018 00019 You should have received a copy of the GNU Library General Public License 00020 along with this library; see the file COPYING.LIB. If not, write to 00021 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00022 Boston, MA 02110-1301, USA. 00023 */ 00024 00025 #include "config.h" 00026 #if ENABLE(SVG) && ENABLE(SVG_ANIMATION) 00027 #include "SVGAnimateTransformElement.h" 00028 00029 #include "AffineTransform.h" 00030 #include "RenderObject.h" 00031 #include "SVGAngle.h" 00032 #include "SVGElementInstance.h" 00033 #include "SVGParserUtilities.h" 00034 #include "SVGSVGElement.h" 00035 #include "SVGStyledTransformableElement.h" 00036 #include "SVGTextElement.h" 00037 #include "SVGTransform.h" 00038 #include "SVGTransformList.h" 00039 #include "SVGUseElement.h" 00040 00041 #include <math.h> 00042 #include <wtf/MathExtras.h> 00043 00044 using namespace std; 00045 00046 namespace WebCore { 00047 00048 SVGAnimateTransformElement::SVGAnimateTransformElement(const QualifiedName& tagName, Document* doc) 00049 : SVGAnimationElement(tagName, doc) 00050 , m_type(SVGTransform::SVG_TRANSFORM_UNKNOWN) 00051 , m_baseIndexInTransformList(0) 00052 { 00053 } 00054 00055 SVGAnimateTransformElement::~SVGAnimateTransformElement() 00056 { 00057 } 00058 00059 bool SVGAnimateTransformElement::hasValidTarget() const 00060 { 00061 SVGElement* targetElement = this->targetElement(); 00062 return SVGAnimationElement::hasValidTarget() && (targetElement->isStyledTransformable() || targetElement->hasTagName(SVGNames::textTag)); 00063 } 00064 00065 void SVGAnimateTransformElement::parseMappedAttribute(MappedAttribute* attr) 00066 { 00067 if (attr->name() == SVGNames::typeAttr) { 00068 if (attr->value() == "translate") 00069 m_type = SVGTransform::SVG_TRANSFORM_TRANSLATE; 00070 else if (attr->value() == "scale") 00071 m_type = SVGTransform::SVG_TRANSFORM_SCALE; 00072 else if (attr->value() == "rotate") 00073 m_type = SVGTransform::SVG_TRANSFORM_ROTATE; 00074 else if (attr->value() == "skewX") 00075 m_type = SVGTransform::SVG_TRANSFORM_SKEWX; 00076 else if (attr->value() == "skewY") 00077 m_type = SVGTransform::SVG_TRANSFORM_SKEWY; 00078 } else 00079 SVGAnimationElement::parseMappedAttribute(attr); 00080 } 00081 00082 00083 static PassRefPtr<SVGTransformList> transformListFor(SVGElement* element) 00084 { 00085 ASSERT(element); 00086 if (element->isStyledTransformable()) 00087 return static_cast<SVGStyledTransformableElement*>(element)->transform(); 00088 if (element->hasTagName(SVGNames::textTag)) 00089 return static_cast<SVGTextElement*>(element)->transform(); 00090 return 0; 00091 } 00092 00093 void SVGAnimateTransformElement::resetToBaseValue(const String& baseValue) 00094 { 00095 if (!hasValidTarget()) 00096 return; 00097 if (baseValue.isEmpty()) { 00098 ExceptionCode ec; 00099 RefPtr<SVGTransformList> list = transformListFor(targetElement()); 00100 list->clear(ec); 00101 } else 00102 targetElement()->setAttribute(SVGNames::transformAttr, baseValue); 00103 } 00104 00105 void SVGAnimateTransformElement::calculateAnimatedValue(float percentage, unsigned repeat, SVGSMILElement* resultElement) 00106 { 00107 if (!hasValidTarget()) 00108 return; 00109 SVGElement* targetElement = resultElement->targetElement(); 00110 RefPtr<SVGTransformList> transformList = transformListFor(targetElement); 00111 ASSERT(transformList); 00112 00113 ExceptionCode ec; 00114 if (!isAdditive()) 00115 transformList->clear(ec); 00116 if (isAccumulated() && repeat) { 00117 SVGTransform accumulatedTransform = SVGTransformDistance(m_fromTransform, m_toTransform).scaledDistance(repeat).addToSVGTransform(SVGTransform()); 00118 transformList->appendItem(accumulatedTransform, ec); 00119 } 00120 SVGTransform transform = SVGTransformDistance(m_fromTransform, m_toTransform).scaledDistance(percentage).addToSVGTransform(m_fromTransform); 00121 transformList->appendItem(transform, ec); 00122 } 00123 00124 bool SVGAnimateTransformElement::calculateFromAndToValues(const String& fromString, const String& toString) 00125 { 00126 m_fromTransform = parseTransformValue(fromString); 00127 if (!m_fromTransform.isValid()) 00128 return false; 00129 m_toTransform = parseTransformValue(toString); 00130 return m_toTransform.isValid(); 00131 } 00132 00133 bool SVGAnimateTransformElement::calculateFromAndByValues(const String& fromString, const String& byString) 00134 { 00135 00136 m_fromTransform = parseTransformValue(fromString); 00137 if (!m_fromTransform.isValid()) 00138 return false; 00139 m_toTransform = SVGTransformDistance::addSVGTransforms(m_fromTransform, parseTransformValue(byString)); 00140 return m_toTransform.isValid(); 00141 } 00142 00143 SVGTransform SVGAnimateTransformElement::parseTransformValue(const String& value) const 00144 { 00145 if (value.isEmpty()) 00146 return SVGTransform(m_type); 00147 SVGTransform result; 00148 // FIXME: This is pretty dumb but parseTransformValue() wants those parenthesis. 00149 String parseString("(" + value + ")"); 00150 const UChar* ptr = parseString.characters(); 00151 SVGTransformable::parseTransformValue(m_type, ptr, ptr + parseString.length(), result); // ignoring return value 00152 return result; 00153 } 00154 00155 void SVGAnimateTransformElement::applyResultsToTarget() 00156 { 00157 if (!hasValidTarget()) 00158 return; 00159 // We accumulate to the target element transform list so there is not much to do here. 00160 SVGElement* targetElement = this->targetElement(); 00161 if (targetElement->renderer()) 00162 targetElement->renderer()->setNeedsLayout(true); 00163 00164 // ...except in case where we have additional instances in <use> trees. 00165 HashSet<SVGElementInstance*>* instances = document()->accessSVGExtensions()->instancesForElement(targetElement); 00166 if (!instances) 00167 return; 00168 RefPtr<SVGTransformList> transformList = transformListFor(targetElement); 00169 HashSet<SVGElementInstance*>::iterator end = instances->end(); 00170 for (HashSet<SVGElementInstance*>::iterator it = instances->begin(); it != end; ++it) { 00171 SVGElement* shadowTreeElement = (*it)->shadowTreeElement(); 00172 ASSERT(shadowTreeElement); 00173 if (shadowTreeElement->isStyledTransformable()) 00174 static_cast<SVGStyledTransformableElement*>(shadowTreeElement)->setTransform(transformList.get()); 00175 else if (shadowTreeElement->hasTagName(SVGNames::textTag)) 00176 static_cast<SVGTextElement*>(shadowTreeElement)->setTransform(transformList.get()); 00177 if (shadowTreeElement->renderer()) 00178 shadowTreeElement->renderer()->setNeedsLayout(true); 00179 } 00180 } 00181 00182 float SVGAnimateTransformElement::calculateDistance(const String& fromString, const String& toString) 00183 { 00184 // FIXME: This is not correct in all cases. The spec demands that each component (translate x and y for example) 00185 // is paced separately. To implement this we need to treat each component as individual animation everywhere. 00186 SVGTransform from = parseTransformValue(fromString); 00187 if (!from.isValid()) 00188 return -1.f; 00189 SVGTransform to = parseTransformValue(toString); 00190 if (!to.isValid() || from.type() != to.type()) 00191 return -1.f; 00192 if (to.type() == SVGTransform::SVG_TRANSFORM_TRANSLATE) { 00193 FloatSize diff = to.translate() - from.translate(); 00194 return sqrtf(diff.width() * diff.width() + diff.height() * diff.height()); 00195 } 00196 if (to.type() == SVGTransform::SVG_TRANSFORM_ROTATE) 00197 return fabsf(to.angle() - from.angle()); 00198 if (to.type() == SVGTransform::SVG_TRANSFORM_SCALE) { 00199 FloatSize diff = to.scale() - from.scale(); 00200 return sqrtf(diff.width() * diff.width() + diff.height() * diff.height()); 00201 } 00202 return -1.f; 00203 } 00204 00205 } 00206 00207 // vim:ts=4:noet 00208 #endif // ENABLE(SVG) 00209
KDE 4.6 API Reference