diff -r 000000000000 -r 4f2f89ce4247 WebCore/svg/SVGAnimateTransformElement.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebCore/svg/SVGAnimateTransformElement.cpp Fri Sep 17 09:02:29 2010 +0300 @@ -0,0 +1,231 @@ +/* + Copyright (C) 2004, 2005 Nikolas Zimmermann + 2004, 2005, 2006, 2007 Rob Buis + Copyright (C) 2007 Eric Seidel + Copyright (C) 2008 Apple Inc. All Rights Reserved. + + This file is part of the WebKit project + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" + +#if ENABLE(SVG) && ENABLE(SVG_ANIMATION) +#include "SVGAnimateTransformElement.h" + +#include "AffineTransform.h" +#include "Attribute.h" +#include "RenderObject.h" +#include "RenderSVGResource.h" +#include "SVGAngle.h" +#include "SVGElementInstance.h" +#include "SVGGradientElement.h" +#include "SVGParserUtilities.h" +#include "SVGSVGElement.h" +#include "SVGStyledTransformableElement.h" +#include "SVGTextElement.h" +#include "SVGTransform.h" +#include "SVGTransformList.h" +#include "SVGUseElement.h" +#include +#include + +using namespace std; + +namespace WebCore { + +SVGAnimateTransformElement::SVGAnimateTransformElement(const QualifiedName& tagName, Document* doc) + : SVGAnimationElement(tagName, doc) + , m_type(SVGTransform::SVG_TRANSFORM_UNKNOWN) + , m_baseIndexInTransformList(0) +{ +} + +SVGAnimateTransformElement::~SVGAnimateTransformElement() +{ +} + +bool SVGAnimateTransformElement::hasValidTarget() const +{ + SVGElement* targetElement = this->targetElement(); + return SVGAnimationElement::hasValidTarget() + && (targetElement->isStyledTransformable() + || targetElement->hasTagName(SVGNames::textTag) + || targetElement->hasTagName(SVGNames::linearGradientTag) + || targetElement->hasTagName(SVGNames::radialGradientTag)); +} + +void SVGAnimateTransformElement::parseMappedAttribute(Attribute* attr) +{ + if (attr->name() == SVGNames::typeAttr) { + if (attr->value() == "translate") + m_type = SVGTransform::SVG_TRANSFORM_TRANSLATE; + else if (attr->value() == "scale") + m_type = SVGTransform::SVG_TRANSFORM_SCALE; + else if (attr->value() == "rotate") + m_type = SVGTransform::SVG_TRANSFORM_ROTATE; + else if (attr->value() == "skewX") + m_type = SVGTransform::SVG_TRANSFORM_SKEWX; + else if (attr->value() == "skewY") + m_type = SVGTransform::SVG_TRANSFORM_SKEWY; + } else + SVGAnimationElement::parseMappedAttribute(attr); +} + + +static PassRefPtr transformListFor(SVGElement* element) +{ + ASSERT(element); + if (element->isStyledTransformable()) + return static_cast(element)->transform(); + if (element->hasTagName(SVGNames::textTag)) + return static_cast(element)->transform(); + if (element->hasTagName(SVGNames::linearGradientTag) || element->hasTagName(SVGNames::radialGradientTag)) + return static_cast(element)->gradientTransform(); + return 0; +} + +void SVGAnimateTransformElement::resetToBaseValue(const String& baseValue) +{ + if (!hasValidTarget()) + return; + + if (targetElement()->hasTagName(SVGNames::linearGradientTag) || targetElement()->hasTagName(SVGNames::radialGradientTag)) { + targetElement()->setAttribute(SVGNames::gradientTransformAttr, baseValue.isEmpty() ? "matrix(1 0 0 1 0 0)" : baseValue); + return; + } + + if (baseValue.isEmpty()) { + ExceptionCode ec; + RefPtr list = transformListFor(targetElement()); + list->clear(ec); + } else + targetElement()->setAttribute(SVGNames::transformAttr, baseValue); +} + +void SVGAnimateTransformElement::calculateAnimatedValue(float percentage, unsigned repeat, SVGSMILElement* resultElement) +{ + if (!hasValidTarget()) + return; + SVGElement* targetElement = resultElement->targetElement(); + RefPtr transformList = transformListFor(targetElement); + ASSERT(transformList); + + ExceptionCode ec; + if (!isAdditive()) + transformList->clear(ec); + if (isAccumulated() && repeat) { + SVGTransform accumulatedTransform = SVGTransformDistance(m_fromTransform, m_toTransform).scaledDistance(repeat).addToSVGTransform(SVGTransform()); + transformList->appendItem(accumulatedTransform, ec); + } + SVGTransform transform = SVGTransformDistance(m_fromTransform, m_toTransform).scaledDistance(percentage).addToSVGTransform(m_fromTransform); + transformList->appendItem(transform, ec); +} + +bool SVGAnimateTransformElement::calculateFromAndToValues(const String& fromString, const String& toString) +{ + m_fromTransform = parseTransformValue(fromString); + if (!m_fromTransform.isValid()) + return false; + m_toTransform = parseTransformValue(toString); + return m_toTransform.isValid(); +} + +bool SVGAnimateTransformElement::calculateFromAndByValues(const String& fromString, const String& byString) +{ + + m_fromTransform = parseTransformValue(fromString); + if (!m_fromTransform.isValid()) + return false; + m_toTransform = SVGTransformDistance::addSVGTransforms(m_fromTransform, parseTransformValue(byString)); + return m_toTransform.isValid(); +} + +SVGTransform SVGAnimateTransformElement::parseTransformValue(const String& value) const +{ + if (value.isEmpty()) + return SVGTransform(m_type); + SVGTransform result; + // FIXME: This is pretty dumb but parseTransformValue() wants those parenthesis. + String parseString("(" + value + ")"); + const UChar* ptr = parseString.characters(); + SVGTransformable::parseTransformValue(m_type, ptr, ptr + parseString.length(), result); // ignoring return value + return result; +} + +void SVGAnimateTransformElement::applyResultsToTarget() +{ + if (!hasValidTarget()) + return; + // We accumulate to the target element transform list so there is not much to do here. + SVGElement* targetElement = this->targetElement(); + if (!targetElement) + return; + + if (RenderObject* renderer = targetElement->renderer()) { + renderer->setNeedsTransformUpdate(); + RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer); + } + + // ...except in case where we have additional instances in trees. + const HashSet& instances = targetElement->instancesForElement(); + RefPtr transformList = transformListFor(targetElement); + const HashSet::const_iterator end = instances.end(); + for (HashSet::const_iterator it = instances.begin(); it != end; ++it) { + SVGElement* shadowTreeElement = (*it)->shadowTreeElement(); + ASSERT(shadowTreeElement); + if (shadowTreeElement->isStyledTransformable()) + static_cast(shadowTreeElement)->setTransformBaseValue(transformList.get()); + else if (shadowTreeElement->hasTagName(SVGNames::textTag)) + static_cast(shadowTreeElement)->setTransformBaseValue(transformList.get()); + else if (shadowTreeElement->hasTagName(SVGNames::linearGradientTag) || shadowTreeElement->hasTagName(SVGNames::radialGradientTag)) + static_cast(shadowTreeElement)->setGradientTransformBaseValue(transformList.get()); + if (RenderObject* renderer = shadowTreeElement->renderer()) { + renderer->setNeedsTransformUpdate(); + RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer); + } + } +} + +float SVGAnimateTransformElement::calculateDistance(const String& fromString, const String& toString) +{ + // FIXME: This is not correct in all cases. The spec demands that each component (translate x and y for example) + // is paced separately. To implement this we need to treat each component as individual animation everywhere. + SVGTransform from = parseTransformValue(fromString); + if (!from.isValid()) + return -1.f; + SVGTransform to = parseTransformValue(toString); + if (!to.isValid() || from.type() != to.type()) + return -1.f; + if (to.type() == SVGTransform::SVG_TRANSFORM_TRANSLATE) { + FloatSize diff = to.translate() - from.translate(); + return sqrtf(diff.width() * diff.width() + diff.height() * diff.height()); + } + if (to.type() == SVGTransform::SVG_TRANSFORM_ROTATE) + return fabsf(to.angle() - from.angle()); + if (to.type() == SVGTransform::SVG_TRANSFORM_SCALE) { + FloatSize diff = to.scale() - from.scale(); + return sqrtf(diff.width() * diff.width() + diff.height() * diff.height()); + } + return -1.f; +} + +} + +// vim:ts=4:noet +#endif // ENABLE(SVG) +