SVGAnimateTransformElement.cpp [plain text]
#include "config.h"
#if ENABLE(SVG) && ENABLE(SVG_ANIMATION)
#include "SVGAnimateTransformElement.h"
#include "AffineTransform.h"
#include "MappedAttribute.h"
#include "RenderObject.h"
#include "SVGAngle.h"
#include "SVGElementInstance.h"
#include "SVGParserUtilities.h"
#include "SVGSVGElement.h"
#include "SVGStyledTransformableElement.h"
#include "SVGTextElement.h"
#include "SVGTransform.h"
#include "SVGTransformList.h"
#include "SVGUseElement.h"
#include <math.h>
#include <wtf/MathExtras.h>
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));
}
void SVGAnimateTransformElement::parseMappedAttribute(MappedAttribute* 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<SVGTransformList> transformListFor(SVGElement* element)
{
ASSERT(element);
if (element->isStyledTransformable())
return static_cast<SVGStyledTransformableElement*>(element)->transform();
if (element->hasTagName(SVGNames::textTag))
return static_cast<SVGTextElement*>(element)->transform();
return 0;
}
void SVGAnimateTransformElement::resetToBaseValue(const String& baseValue)
{
if (!hasValidTarget())
return;
if (baseValue.isEmpty()) {
ExceptionCode ec;
RefPtr<SVGTransformList> 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<SVGTransformList> 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;
String parseString("(" + value + ")");
const UChar* ptr = parseString.characters();
SVGTransformable::parseTransformValue(m_type, ptr, ptr + parseString.length(), result); return result;
}
void SVGAnimateTransformElement::applyResultsToTarget()
{
if (!hasValidTarget())
return;
SVGElement* targetElement = this->targetElement();
if (RenderObject* renderer = targetElement->renderer()) {
renderer->setNeedsTransformUpdate();
renderer->setNeedsLayout(true);
}
const HashSet<SVGElementInstance*>& instances = targetElement->instancesForElement();
RefPtr<SVGTransformList> transformList = transformListFor(targetElement);
const HashSet<SVGElementInstance*>::const_iterator end = instances.end();
for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) {
SVGElement* shadowTreeElement = (*it)->shadowTreeElement();
ASSERT(shadowTreeElement);
if (shadowTreeElement->isStyledTransformable())
static_cast<SVGStyledTransformableElement*>(shadowTreeElement)->setTransformBaseValue(transformList.get());
else if (shadowTreeElement->hasTagName(SVGNames::textTag))
static_cast<SVGTextElement*>(shadowTreeElement)->setTransformBaseValue(transformList.get());
if (RenderObject* renderer = shadowTreeElement->renderer()) {
renderer->setNeedsTransformUpdate();
renderer->setNeedsLayout(true);
}
}
}
float SVGAnimateTransformElement::calculateDistance(const String& fromString, const String& toString)
{
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;
}
}
#endif // ENABLE(SVG)