/* Copyright (C) 2008 Nikolas Zimmermann <zimmermann@kde.org> 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<typename OwnerTypeArg, typename AnimatedTypeArg, const char* TagName, const char* PropertyName> class SVGAnimatedProperty; template<typename OwnerType, typename OwnerElement, typename AnimatedType, typename DecoratedType, const char* TagName, const char* PropertyName> class SVGAnimatedPropertyTearOff : public SVGAnimatedTemplate<DecoratedType> { public: typedef SVGAnimatedPropertyTearOff<OwnerType, OwnerElement, AnimatedType, DecoratedType, TagName, PropertyName> Self; typedef SVGAnimatedProperty<OwnerType, AnimatedType, TagName, PropertyName> Creator; static PassRefPtr<Self> 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<OwnerElement> 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<typename OwnerType, bool isDerivedFromSVGElement> struct GetOwnerElementForType; template<typename OwnerType> struct IsDerivedFromSVGElement; // Helper template used for synchronizing SVG <-> XML properties template<typename OwnerElement, typename DecoratedType> void synchronizeProperty(const OwnerElement* ownerElement, const QualifiedName& attributeName, DecoratedType baseValue); // Abstract base class class SVGAnimatedPropertyBase : public Noncopyable { public: virtual ~SVGAnimatedPropertyBase() { } virtual void synchronize() const = 0; }; template<typename OwnerTypeArg, typename AnimatedTypeArg, const char* TagName, const char* PropertyName> class SVGAnimatedProperty : public SVGAnimatedPropertyBase { public: typedef OwnerTypeArg OwnerType; typedef AnimatedTypeArg AnimatedType; typedef typename SVGAnimatedTypeValue<AnimatedType>::StorableType StorableType; typedef typename SVGAnimatedTypeValue<AnimatedType>::DecoratedType DecoratedType; typedef GetOwnerElementForType<OwnerType, IsDerivedFromSVGElement<OwnerType>::value> OwnerElementForType; typedef typename OwnerElementForType::OwnerElement OwnerElement; typedef SVGAnimatedPropertyTearOff<OwnerType, OwnerElement, AnimatedType, DecoratedType, TagName, PropertyName> 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<typename T1> SVGAnimatedProperty(const OwnerType*, const QualifiedName& attributeName, const T1&); template<typename T1> SVGAnimatedProperty(const OwnerType*, const QualifiedName& attributeName, const AtomicString& attributeIdentifier, const T1&); template<typename T1, typename T2> SVGAnimatedProperty(const OwnerType*, const QualifiedName& attributeName, const T1&, const T2&); template<typename T1, typename T2> SVGAnimatedProperty(const OwnerType*, const QualifiedName& attributeName, const AtomicString& attributeIdentifier, const T1&, const T2&); template<typename T1, typename T2, typename T3> SVGAnimatedProperty(const OwnerType*, const QualifiedName& attributeName, const T1&, const T2&, const T3&); template<typename T1, typename T2, typename T3> 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<TearOff> 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<StorableType> m_value; }; // SVGAnimatedPropertyTearOff implementation template<typename OwnerType, typename OwnerElement, typename AnimatedType, typename DecoratedType, const char* TagName, const char* PropertyName> SVGAnimatedPropertyTearOff<OwnerType, OwnerElement, AnimatedType, DecoratedType, TagName, PropertyName>::SVGAnimatedPropertyTearOff(const Creator& creator, const OwnerElement* owner, const QualifiedName& attributeName) : SVGAnimatedTemplate<DecoratedType>(attributeName) , m_creator(const_cast<Creator&>(creator)) , m_ownerElement(const_cast<OwnerElement*>(owner)) { ASSERT(m_ownerElement); } template<typename OwnerType, typename OwnerElement, typename AnimatedType, typename DecoratedType, const char* TagName, const char* PropertyName> DecoratedType SVGAnimatedPropertyTearOff<OwnerType, OwnerElement, AnimatedType, DecoratedType, TagName, PropertyName>::baseVal() const { return m_creator.baseValue(); } template<typename OwnerType, typename OwnerElement, typename AnimatedType, typename DecoratedType, const char* TagName, const char* PropertyName> void SVGAnimatedPropertyTearOff<OwnerType, OwnerElement, AnimatedType, DecoratedType, TagName, PropertyName>::setBaseVal(DecoratedType newBaseVal) { m_creator.setBaseValue(newBaseVal); } template<typename OwnerType, typename OwnerElement, typename AnimatedType, typename DecoratedType, const char* TagName, const char* PropertyName> DecoratedType SVGAnimatedPropertyTearOff<OwnerType, OwnerElement, AnimatedType, DecoratedType, TagName, PropertyName>::animVal() const { return m_creator.value(); } template<typename OwnerType, typename OwnerElement, typename AnimatedType, typename DecoratedType, const char* TagName, const char* PropertyName> void SVGAnimatedPropertyTearOff<OwnerType, OwnerElement, AnimatedType, DecoratedType, TagName, PropertyName>::setAnimVal(DecoratedType newAnimVal) { m_creator.setValue(newAnimVal); } // SVGAnimatedProperty implementation template<typename OwnerTypeArg, typename AnimatedTypeArg, const char* TagName, const char* PropertyName> SVGAnimatedProperty<OwnerTypeArg, AnimatedTypeArg, TagName, PropertyName>::SVGAnimatedProperty(const OwnerType* owner, const QualifiedName& attributeName) : m_ownerType(owner) , m_attributeName(attributeName) , m_attributeIdentifier(attributeName.localName()) , m_value() { ASSERT(m_ownerType); } template<typename OwnerTypeArg, typename AnimatedTypeArg, const char* TagName, const char* PropertyName> SVGAnimatedProperty<OwnerTypeArg, AnimatedTypeArg, TagName, PropertyName>::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<typename OwnerTypeArg, typename AnimatedTypeArg, const char* TagName, const char* PropertyName> template<typename T1> SVGAnimatedProperty<OwnerTypeArg, AnimatedTypeArg, TagName, PropertyName>::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<typename OwnerTypeArg, typename AnimatedTypeArg, const char* TagName, const char* PropertyName> template<typename T1> SVGAnimatedProperty<OwnerTypeArg, AnimatedTypeArg, TagName, PropertyName>::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<typename OwnerTypeArg, typename AnimatedTypeArg, const char* TagName, const char* PropertyName> template<typename T1, typename T2> SVGAnimatedProperty<OwnerTypeArg, AnimatedTypeArg, TagName, PropertyName>::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<typename OwnerTypeArg, typename AnimatedTypeArg, const char* TagName, const char* PropertyName> template<typename T1, typename T2> SVGAnimatedProperty<OwnerTypeArg, AnimatedTypeArg, TagName, PropertyName>::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<typename OwnerTypeArg, typename AnimatedTypeArg, const char* TagName, const char* PropertyName> template<typename T1, typename T2, typename T3> SVGAnimatedProperty<OwnerTypeArg, AnimatedTypeArg, TagName, PropertyName>::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<typename OwnerTypeArg, typename AnimatedTypeArg, const char* TagName, const char* PropertyName> template<typename T1, typename T2, typename T3> SVGAnimatedProperty<OwnerTypeArg, AnimatedTypeArg, TagName, PropertyName>::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 OwnerTypeArg, typename AnimatedTypeArg, const char* TagName, const char* PropertyName> typename SVGAnimatedProperty<OwnerTypeArg, AnimatedTypeArg, TagName, PropertyName>::DecoratedType SVGAnimatedProperty<OwnerTypeArg, AnimatedTypeArg, TagName, PropertyName>::value() const { return m_value; } template<typename OwnerTypeArg, typename AnimatedTypeArg, const char* TagName, const char* PropertyName> void SVGAnimatedProperty<OwnerTypeArg, AnimatedTypeArg, TagName, PropertyName>::setValue(typename SVGAnimatedProperty::DecoratedType newValue) { m_value = newValue; ownerElement()->setSynchronizedSVGAttributes(false); } template<typename OwnerTypeArg, typename AnimatedTypeArg, const char* TagName, const char* PropertyName> typename SVGAnimatedProperty<OwnerTypeArg, AnimatedTypeArg, TagName, PropertyName>::DecoratedType SVGAnimatedProperty<OwnerTypeArg, AnimatedTypeArg, TagName, PropertyName>::baseValue() const { const OwnerElement* ownerElement = this->ownerElement(); SVGDocumentExtensions* extensions = ownerElement->accessDocumentSVGExtensions(); if (extensions && extensions->hasBaseValue<DecoratedType>(ownerElement, m_attributeIdentifier)) return extensions->baseValue<DecoratedType>(ownerElement, m_attributeIdentifier); return m_value; } template<typename OwnerTypeArg, typename AnimatedTypeArg, const char* TagName, const char* PropertyName> void SVGAnimatedProperty<OwnerTypeArg, AnimatedTypeArg, TagName, PropertyName>::setBaseValue(typename SVGAnimatedProperty::DecoratedType newValue) { const OwnerElement* ownerElement = this->ownerElement(); SVGDocumentExtensions* extensions = ownerElement->accessDocumentSVGExtensions(); if (extensions && extensions->hasBaseValue<DecoratedType>(ownerElement, m_attributeIdentifier)) { extensions->setBaseValue<DecoratedType>(ownerElement, m_attributeIdentifier, newValue); return; } // Only update stored property, if not animating m_value = newValue; ownerElement->setSynchronizedSVGAttributes(false); } template<typename OwnerTypeArg, typename AnimatedTypeArg, const char* TagName, const char* PropertyName> PassRefPtr<typename SVGAnimatedProperty<OwnerTypeArg, AnimatedTypeArg, TagName, PropertyName>::TearOff> SVGAnimatedProperty<OwnerTypeArg, AnimatedTypeArg, TagName, PropertyName>::animatedTearOff() const { return lookupOrCreateWrapper<OwnerTypeArg, AnimatedTypeArg, TagName, PropertyName, TearOff, OwnerElement>(*this, ownerElement(), m_attributeName, m_attributeIdentifier); } template<typename OwnerTypeArg, typename AnimatedTypeArg, const char* TagName, const char* PropertyName> void SVGAnimatedProperty<OwnerTypeArg, AnimatedTypeArg, TagName, PropertyName>::synchronize() const { if (!m_value.needsSynchronization()) return; synchronizeProperty<OwnerElement, DecoratedType>(ownerElement(), m_attributeName, baseValue()); m_value.setSynchronized(); } template<typename OwnerTypeArg, typename AnimatedTypeArg, const char* TagName, const char* PropertyName> void SVGAnimatedProperty<OwnerTypeArg, AnimatedTypeArg, TagName, PropertyName>::startAnimation() const { const OwnerElement* ownerElement = this->ownerElement(); SVGDocumentExtensions* extensions = ownerElement->accessDocumentSVGExtensions(); if (extensions) { ASSERT(!extensions->hasBaseValue<DecoratedType>(ownerElement, m_attributeIdentifier)); extensions->setBaseValue<DecoratedType>(ownerElement, m_attributeIdentifier, m_value); } } template<typename OwnerTypeArg, typename AnimatedTypeArg, const char* TagName, const char* PropertyName> void SVGAnimatedProperty<OwnerTypeArg, AnimatedTypeArg, TagName, PropertyName>::stopAnimation() { const OwnerElement* ownerElement = this->ownerElement(); SVGDocumentExtensions* extensions = ownerElement->accessDocumentSVGExtensions(); if (extensions) { ASSERT(extensions->hasBaseValue<DecoratedType>(ownerElement, m_attributeIdentifier)); setValue(extensions->baseValue<DecoratedType>(ownerElement, m_attributeIdentifier)); extensions->removeBaseValue<AnimatedType>(ownerElement, m_attributeIdentifier); } } template<typename OwnerTypeArg, typename AnimatedTypeArg, const char* TagName, const char* PropertyName> const typename SVGAnimatedProperty<OwnerTypeArg, AnimatedTypeArg, TagName, PropertyName>::OwnerElement* SVGAnimatedProperty<OwnerTypeArg, AnimatedTypeArg, TagName, PropertyName>::ownerElement() const { return OwnerElementForType::ownerElement(m_ownerType); } // GetOwnerElementForType implementation template<typename OwnerType> struct GetOwnerElementForType<OwnerType, true> : Noncopyable { typedef OwnerType OwnerElement; static const OwnerElement* ownerElement(const OwnerType* type) { return type; } }; template<typename OwnerType> struct GetOwnerElementForType<OwnerType, false> : Noncopyable { typedef SVGElement OwnerElement; static const OwnerElement* ownerElement(const OwnerType* type) { const OwnerElement* context = type->contextElement(); ASSERT(context); return context; } }; // IsDerivedFromSVGElement implementation template<typename OwnerType> struct IsDerivedFromSVGElement : Noncopyable { static const bool value = true; }; class SVGExternalResourcesRequired; template<> struct IsDerivedFromSVGElement<SVGExternalResourcesRequired> : Noncopyable { static const bool value = false; }; class SVGFitToViewBox; template<> struct IsDerivedFromSVGElement<SVGFitToViewBox> : Noncopyable { static const bool value = false; }; class SVGURIReference; template<> struct IsDerivedFromSVGElement<SVGURIReference> : Noncopyable { static const bool value = false; }; // Central function handling the main SVG<->XML synchronization part. template<typename OwnerElement, typename DecoratedType> void synchronizeProperty(const OwnerElement* ownerElement, const QualifiedName& attributeName, DecoratedType baseValue) { AtomicString value(SVGAnimatedTypeValue<DecoratedType>::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*>(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<OwnerType, AnimatedType, ElementTag, AttributeTag> SVGAnimatedProperty##UpperProperty; \ typedef SVGAnimatedTypeValue<AnimatedType>::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<SVGAnimatedProperty##UpperProperty::TearOff> LowerProperty##Animated() const { return m_##LowerProperty.animatedTearOff(); } \ void synchronize##UpperProperty() const { m_##LowerProperty.synchronize(); } }; #endif #endif