/* Copyright (C) 2008 Nikolas Zimmermann 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. */ #ifndef SVGAnimatedProperty_h #define SVGAnimatedProperty_h #if ENABLE(SVG) #include "SVGAnimatedTemplate.h" #include "SVGDocumentExtensions.h" #include "SynchronizableTypeWrapper.h" namespace WebCore { template class SVGAnimatedProperty; template class SVGAnimatedPropertyTearOff : public SVGAnimatedTemplate { public: typedef SVGAnimatedPropertyTearOff Self; typedef SVGAnimatedProperty Creator; static PassRefPtr create(const Creator& creator, const OwnerElement* owner, const QualifiedName& attributeName) { return adoptRef(new Self(creator, owner, attributeName)); } virtual DecoratedType baseVal() const; virtual void setBaseVal(DecoratedType); virtual DecoratedType animVal() const; virtual void setAnimVal(DecoratedType); private: SVGAnimatedPropertyTearOff(const Creator&, const OwnerElement*, const QualifiedName& attributeName); Creator& m_creator; RefPtr m_ownerElement; }; // Helper templates mapping owner types to owner elements (for SVG*Element OwnerType is equal to OwnerElement, for non-SVG*Element derived types, they're different) template struct GetOwnerElementForType; template struct IsDerivedFromSVGElement; // Helper template used for synchronizing SVG <-> XML properties template void synchronizeProperty(const OwnerElement* ownerElement, const QualifiedName& attributeName, DecoratedType baseValue); // Abstract base class class SVGAnimatedPropertyBase : Noncopyable { public: virtual ~SVGAnimatedPropertyBase() { } virtual void synchronize() const = 0; }; template class SVGAnimatedProperty : public SVGAnimatedPropertyBase { public: typedef OwnerTypeArg OwnerType; typedef AnimatedTypeArg AnimatedType; typedef typename SVGAnimatedTypeValue::StorableType StorableType; typedef typename SVGAnimatedTypeValue::DecoratedType DecoratedType; typedef GetOwnerElementForType::value> OwnerElementForType; typedef typename OwnerElementForType::OwnerElement OwnerElement; typedef SVGAnimatedPropertyTearOff TearOff; // attributeName & attributeIdentifier may differ. For SVGMarkerElement, there are two exposed SVG animatable // properties: orientType & orientAngle, though only one DOM attribute "orient", handle these cases! SVGAnimatedProperty(const OwnerType*, const QualifiedName& attributeName); SVGAnimatedProperty(const OwnerType*, const QualifiedName& attributeName, const AtomicString& attributeIdentifier); // "Forwarding constructors" for primitive type assignment with more than one argument template SVGAnimatedProperty(const OwnerType*, const QualifiedName& attributeName, const T1&); template SVGAnimatedProperty(const OwnerType*, const QualifiedName& attributeName, const AtomicString& attributeIdentifier, const T1&); template SVGAnimatedProperty(const OwnerType*, const QualifiedName& attributeName, const T1&, const T2&); template SVGAnimatedProperty(const OwnerType*, const QualifiedName& attributeName, const AtomicString& attributeIdentifier, const T1&, const T2&); template SVGAnimatedProperty(const OwnerType*, const QualifiedName& attributeName, const T1&, const T2&, const T3&); template SVGAnimatedProperty(const OwnerType*, const QualifiedName& attributeName, const AtomicString& attributeIdentifier, const T1&, const T2&, const T3&); DecoratedType value() const; void setValue(DecoratedType); DecoratedType baseValue() const; void setBaseValue(DecoratedType); // Tear offs only used by bindings, never in internal code PassRefPtr animatedTearOff() const; virtual void synchronize() const; void startAnimation() const; void stopAnimation(); private: const OwnerElement* ownerElement() const; private: // We're a member variable on stack, living in OwnerType, NO need to ref here. const OwnerType* m_ownerType; const QualifiedName& m_attributeName; const AtomicString& m_attributeIdentifier; mutable SynchronizableTypeWrapper m_value; }; // SVGAnimatedPropertyTearOff implementation template SVGAnimatedPropertyTearOff::SVGAnimatedPropertyTearOff(const Creator& creator, const OwnerElement* owner, const QualifiedName& attributeName) : SVGAnimatedTemplate(attributeName) , m_creator(const_cast(creator)) , m_ownerElement(const_cast(owner)) { ASSERT(m_ownerElement); } template DecoratedType SVGAnimatedPropertyTearOff::baseVal() const { return m_creator.baseValue(); } template void SVGAnimatedPropertyTearOff::setBaseVal(DecoratedType newBaseVal) { m_creator.setBaseValue(newBaseVal); } template DecoratedType SVGAnimatedPropertyTearOff::animVal() const { return m_creator.value(); } template void SVGAnimatedPropertyTearOff::setAnimVal(DecoratedType newAnimVal) { m_creator.setValue(newAnimVal); } // SVGAnimatedProperty implementation template SVGAnimatedProperty::SVGAnimatedProperty(const OwnerType* owner, const QualifiedName& attributeName) : m_ownerType(owner) , m_attributeName(attributeName) , m_attributeIdentifier(attributeName.localName()) , m_value() { ASSERT(m_ownerType); } template SVGAnimatedProperty::SVGAnimatedProperty(const OwnerType* owner, const QualifiedName& attributeName, const AtomicString& attributeIdentifier) : m_ownerType(owner) , m_attributeName(attributeName) , m_attributeIdentifier(attributeIdentifier) , m_value() { ASSERT(m_ownerType); } template template SVGAnimatedProperty::SVGAnimatedProperty(const OwnerType* owner, const QualifiedName& attributeName, const T1& arg1) : m_ownerType(owner) , m_attributeName(attributeName) , m_attributeIdentifier(attributeName.localName()) , m_value(arg1) { ASSERT(m_ownerType); } template template SVGAnimatedProperty::SVGAnimatedProperty(const OwnerType* owner, const QualifiedName& attributeName, const AtomicString& attributeIdentifier, const T1& arg1) : m_ownerType(owner) , m_attributeName(attributeName) , m_attributeIdentifier(attributeIdentifier) , m_value(arg1) { ASSERT(m_ownerType); } template template SVGAnimatedProperty::SVGAnimatedProperty(const OwnerType* owner, const QualifiedName& attributeName, const T1& arg1, const T2& arg2) : m_ownerType(owner) , m_attributeName(attributeName) , m_attributeIdentifier(attributeName.localName()) , m_value(arg1, arg2) { ASSERT(m_ownerType); } template template SVGAnimatedProperty::SVGAnimatedProperty(const OwnerType* owner, const QualifiedName& attributeName, const AtomicString& attributeIdentifier, const T1& arg1, const T2& arg2) : m_ownerType(owner) , m_attributeName(attributeName) , m_attributeIdentifier(attributeIdentifier) , m_value(arg1, arg2) { ASSERT(m_ownerType); } template template SVGAnimatedProperty::SVGAnimatedProperty(const OwnerType* owner, const QualifiedName& attributeName, const T1& arg1, const T2& arg2, const T3& arg3) : m_ownerType(owner) , m_attributeName(attributeName) , m_attributeIdentifier(attributeName.localName()) , m_value(arg1, arg2, arg3) { ASSERT(m_ownerType); } template template SVGAnimatedProperty::SVGAnimatedProperty(const OwnerType* owner, const QualifiedName& attributeName, const AtomicString& attributeIdentifier, const T1& arg1, const T2& arg2, const T3& arg3) : m_ownerType(owner) , m_attributeName(attributeName) , m_attributeIdentifier(attributeIdentifier) , m_value(arg1, arg2, arg3) { ASSERT(m_ownerType); } template typename SVGAnimatedProperty::DecoratedType SVGAnimatedProperty::value() const { return m_value; } template void SVGAnimatedProperty::setValue(typename SVGAnimatedProperty::DecoratedType newValue) { m_value = newValue; ownerElement()->setSynchronizedSVGAttributes(false); } template typename SVGAnimatedProperty::DecoratedType SVGAnimatedProperty::baseValue() const { const OwnerElement* ownerElement = this->ownerElement(); SVGDocumentExtensions* extensions = ownerElement->accessDocumentSVGExtensions(); if (extensions && extensions->hasBaseValue(ownerElement, m_attributeIdentifier)) return extensions->baseValue(ownerElement, m_attributeIdentifier); return m_value; } template void SVGAnimatedProperty::setBaseValue(typename SVGAnimatedProperty::DecoratedType newValue) { const OwnerElement* ownerElement = this->ownerElement(); SVGDocumentExtensions* extensions = ownerElement->accessDocumentSVGExtensions(); if (extensions && extensions->hasBaseValue(ownerElement, m_attributeIdentifier)) { extensions->setBaseValue(ownerElement, m_attributeIdentifier, newValue); return; } // Only update stored property, if not animating m_value = newValue; ownerElement->setSynchronizedSVGAttributes(false); } template PassRefPtr::TearOff> SVGAnimatedProperty::animatedTearOff() const { return lookupOrCreateWrapper(*this, ownerElement(), m_attributeName, m_attributeIdentifier); } template void SVGAnimatedProperty::synchronize() const { if (!m_value.needsSynchronization()) return; synchronizeProperty(ownerElement(), m_attributeName, baseValue()); m_value.setSynchronized(); } template void SVGAnimatedProperty::startAnimation() const { const OwnerElement* ownerElement = this->ownerElement(); SVGDocumentExtensions* extensions = ownerElement->accessDocumentSVGExtensions(); if (extensions) { ASSERT(!extensions->hasBaseValue(ownerElement, m_attributeIdentifier)); extensions->setBaseValue(ownerElement, m_attributeIdentifier, m_value); } } template void SVGAnimatedProperty::stopAnimation() { const OwnerElement* ownerElement = this->ownerElement(); SVGDocumentExtensions* extensions = ownerElement->accessDocumentSVGExtensions(); if (extensions) { ASSERT(extensions->hasBaseValue(ownerElement, m_attributeIdentifier)); setValue(extensions->baseValue(ownerElement, m_attributeIdentifier)); extensions->removeBaseValue(ownerElement, m_attributeIdentifier); } } template const typename SVGAnimatedProperty::OwnerElement* SVGAnimatedProperty::ownerElement() const { return OwnerElementForType::ownerElement(m_ownerType); } // GetOwnerElementForType implementation template struct GetOwnerElementForType : Noncopyable { typedef OwnerType OwnerElement; static const OwnerElement* ownerElement(const OwnerType* type) { return type; } }; template struct GetOwnerElementForType : Noncopyable { typedef SVGElement OwnerElement; static const OwnerElement* ownerElement(const OwnerType* type) { const OwnerElement* context = type->contextElement(); ASSERT(context); return context; } }; // IsDerivedFromSVGElement implementation template struct IsDerivedFromSVGElement : Noncopyable { static const bool value = true; }; class SVGExternalResourcesRequired; template<> struct IsDerivedFromSVGElement : Noncopyable { static const bool value = false; }; class SVGFitToViewBox; template<> struct IsDerivedFromSVGElement : Noncopyable { static const bool value = false; }; class SVGURIReference; template<> struct IsDerivedFromSVGElement : Noncopyable { static const bool value = false; }; // Central function handling the main SVG<->XML synchronization part. template void synchronizeProperty(const OwnerElement* ownerElement, const QualifiedName& attributeName, DecoratedType baseValue) { AtomicString value(SVGAnimatedTypeValue::toString(baseValue)); NamedNodeMap* namedAttrMap = ownerElement->attributes(false); Attribute* old = namedAttrMap->getAttributeItem(attributeName); if (old && value.isNull()) namedAttrMap->removeAttribute(old->name()); else if (!old && !value.isNull()) namedAttrMap->addAttribute(const_cast(ownerElement)->createAttribute(attributeName, value)); else if (old && !value.isNull()) old->setValue(value); } // Helper macro used to register animated properties within SVG* classes #define ANIMATED_PROPERTY_DECLARATIONS(OwnerType, ElementTag, AttributeTag, AnimatedType, UpperProperty, LowerProperty) \ private: \ typedef SVGAnimatedProperty SVGAnimatedProperty##UpperProperty; \ typedef SVGAnimatedTypeValue::DecoratedType DecoratedTypeFor##UpperProperty; \ SVGAnimatedProperty##UpperProperty m_##LowerProperty; \ public: \ DecoratedTypeFor##UpperProperty LowerProperty() const { return m_##LowerProperty.value(); } \ void set##UpperProperty(DecoratedTypeFor##UpperProperty type) { m_##LowerProperty.setValue(type); } \ DecoratedTypeFor##UpperProperty LowerProperty##BaseValue() const { return m_##LowerProperty.baseValue(); } \ void set##UpperProperty##BaseValue(DecoratedTypeFor##UpperProperty type) { m_##LowerProperty.setBaseValue(type); } \ PassRefPtr LowerProperty##Animated() const { return m_##LowerProperty.animatedTearOff(); } \ void synchronize##UpperProperty() const { m_##LowerProperty.synchronize(); } }; #endif #endif