| /* |
| 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 : 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 |