summaryrefslogtreecommitdiffstats
path: root/WebCore/svg/properties
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/svg/properties')
-rw-r--r--WebCore/svg/properties/SVGAnimatedListPropertyTearOff.h52
-rw-r--r--WebCore/svg/properties/SVGAnimatedPropertyMacros.h36
-rw-r--r--WebCore/svg/properties/SVGAnimatedPropertySynchronizer.h36
-rw-r--r--WebCore/svg/properties/SVGListProperty.h412
-rw-r--r--WebCore/svg/properties/SVGListPropertyTearOff.h309
-rw-r--r--WebCore/svg/properties/SVGPropertyTearOff.h11
-rw-r--r--WebCore/svg/properties/SVGPropertyTraits.h22
-rw-r--r--WebCore/svg/properties/SVGStaticListPropertyTearOff.h114
-rw-r--r--WebCore/svg/properties/SVGStaticPropertyTearOff.h67
9 files changed, 752 insertions, 307 deletions
diff --git a/WebCore/svg/properties/SVGAnimatedListPropertyTearOff.h b/WebCore/svg/properties/SVGAnimatedListPropertyTearOff.h
index c002d09..0777b6a 100644
--- a/WebCore/svg/properties/SVGAnimatedListPropertyTearOff.h
+++ b/WebCore/svg/properties/SVGAnimatedListPropertyTearOff.h
@@ -23,6 +23,7 @@
#if ENABLE(SVG)
#include "SVGAnimatedProperty.h"
#include "SVGListPropertyTearOff.h"
+#include "SVGStaticListPropertyTearOff.h"
namespace WebCore {
@@ -32,17 +33,21 @@ class SVGPropertyTearOff;
template<typename PropertyType>
class SVGAnimatedListPropertyTearOff : public SVGAnimatedProperty {
public:
+ typedef typename SVGPropertyTraits<PropertyType>::ListItemType ListItemType;
+ typedef SVGPropertyTearOff<ListItemType> ListItemTearOff;
+ typedef Vector<RefPtr<ListItemTearOff> > ListWrapperCache;
+
SVGProperty* baseVal()
{
if (!m_baseVal)
- m_baseVal = SVGListPropertyTearOff<PropertyType>::create(this, BaseValRole, m_property);
+ m_baseVal = SVGListPropertyTearOff<PropertyType>::create(this, BaseValRole);
return m_baseVal.get();
}
SVGProperty* animVal()
{
if (!m_animVal)
- m_animVal = SVGListPropertyTearOff<PropertyType>::create(this, AnimValRole, m_property);
+ m_animVal = SVGListPropertyTearOff<PropertyType>::create(this, AnimValRole);
return m_animVal.get();
}
@@ -50,39 +55,56 @@ public:
int removeItemFromList(SVGProperty* property, bool shouldSynchronizeWrappers)
{
- // FIXME: No animVal support.
- if (!m_baseVal)
- return -1;
-
+ // This should ever be called for our baseVal, as animVal can't modify the list.
typedef SVGPropertyTearOff<typename SVGPropertyTraits<PropertyType>::ListItemType> ListItemTearOff;
return static_pointer_cast<SVGListPropertyTearOff<PropertyType> >(m_baseVal)->removeItemFromList(static_cast<ListItemTearOff*>(property), shouldSynchronizeWrappers);
}
void detachListWrappers(unsigned newListSize)
{
- if (m_baseVal)
- static_pointer_cast<SVGListPropertyTearOff<PropertyType> >(m_baseVal)->detachListWrappers(newListSize);
- if (m_animVal)
- static_pointer_cast<SVGListPropertyTearOff<PropertyType> >(m_animVal)->detachListWrappers(newListSize);
+ // See SVGPropertyTearOff::detachWrapper() for an explaination what's happening here.
+ unsigned size = m_wrappers.size();
+ ASSERT(size == m_values.size());
+ for (unsigned i = 0; i < size; ++i) {
+ RefPtr<ListItemTearOff>& item = m_wrappers.at(i);
+ if (!item)
+ continue;
+ item->detachWrapper();
+ }
+
+ // Reinitialize the wrapper cache to be equal to the new values size, after the XML DOM changed the list.
+ if (newListSize)
+ m_wrappers.fill(0, newListSize);
+ else
+ m_wrappers.clear();
}
+ PropertyType& values() { return m_values; }
+ ListWrapperCache& wrappers() { return m_wrappers; }
+
private:
friend class SVGAnimatedProperty;
- static PassRefPtr<SVGAnimatedListPropertyTearOff<PropertyType> > create(SVGElement* contextElement, const QualifiedName& attributeName, PropertyType& property)
+ static PassRefPtr<SVGAnimatedListPropertyTearOff<PropertyType> > create(SVGElement* contextElement, const QualifiedName& attributeName, PropertyType& values)
{
ASSERT(contextElement);
- return adoptRef(new SVGAnimatedListPropertyTearOff<PropertyType>(contextElement, attributeName, property));
+ return adoptRef(new SVGAnimatedListPropertyTearOff<PropertyType>(contextElement, attributeName, values));
}
- SVGAnimatedListPropertyTearOff(SVGElement* contextElement, const QualifiedName& attributeName, PropertyType& property)
+ SVGAnimatedListPropertyTearOff(SVGElement* contextElement, const QualifiedName& attributeName, PropertyType& values)
: SVGAnimatedProperty(contextElement, attributeName)
- , m_property(property)
+ , m_values(values)
{
+ if (!values.isEmpty())
+ m_wrappers.fill(0, values.size());
}
private:
- PropertyType& m_property;
+ PropertyType& m_values;
+
+ // FIXME: The list wrapper cache is shared between baseVal/animVal. If we implement animVal,
+ // we need two seperated wrapper caches if the attribute gets animated.
+ ListWrapperCache m_wrappers;
RefPtr<SVGProperty> m_baseVal;
RefPtr<SVGProperty> m_animVal;
diff --git a/WebCore/svg/properties/SVGAnimatedPropertyMacros.h b/WebCore/svg/properties/SVGAnimatedPropertyMacros.h
index 12d0565..e1c75b9 100644
--- a/WebCore/svg/properties/SVGAnimatedPropertyMacros.h
+++ b/WebCore/svg/properties/SVGAnimatedPropertyMacros.h
@@ -32,6 +32,42 @@
namespace WebCore {
+class SVGElement;
+
+// GetOwnerElementForType implementation
+template<typename OwnerType, bool isDerivedFromSVGElement>
+struct GetOwnerElementForType;
+
+template<typename OwnerType>
+struct GetOwnerElementForType<OwnerType, true> {
+ static SVGElement* ownerElement(OwnerType* type)
+ {
+ return type;
+ }
+};
+
+template<typename OwnerType>
+struct GetOwnerElementForType<OwnerType, false> {
+ static SVGElement* ownerElement(OwnerType* type)
+ {
+ SVGElement* context = type->contextElement();
+ ASSERT(context);
+ return context;
+ }
+};
+
+// IsDerivedFromSVGElement implementation
+template<typename OwnerType>
+struct IsDerivedFromSVGElement {
+ static const bool value = true;
+};
+
+class SVGViewSpec;
+template<>
+struct IsDerivedFromSVGElement<SVGViewSpec> {
+ static const bool value = false;
+};
+
template<typename PropertyType>
struct SVGSynchronizableAnimatedProperty {
SVGSynchronizableAnimatedProperty()
diff --git a/WebCore/svg/properties/SVGAnimatedPropertySynchronizer.h b/WebCore/svg/properties/SVGAnimatedPropertySynchronizer.h
index 2b816ab..b97073d 100644
--- a/WebCore/svg/properties/SVGAnimatedPropertySynchronizer.h
+++ b/WebCore/svg/properties/SVGAnimatedPropertySynchronizer.h
@@ -23,42 +23,6 @@
#if ENABLE(SVG)
namespace WebCore {
-class SVGElement;
-
-// GetOwnerElementForType implementation
-template<typename OwnerType, bool isDerivedFromSVGElement>
-struct GetOwnerElementForType;
-
-template<typename OwnerType>
-struct GetOwnerElementForType<OwnerType, true> : public Noncopyable {
- static SVGElement* ownerElement(OwnerType* type)
- {
- return type;
- }
-};
-
-template<typename OwnerType>
-struct GetOwnerElementForType<OwnerType, false> : public Noncopyable {
- static SVGElement* ownerElement(OwnerType* type)
- {
- SVGElement* context = type->contextElement();
- ASSERT(context);
- return context;
- }
-};
-
-// IsDerivedFromSVGElement implementation
-template<typename OwnerType>
-struct IsDerivedFromSVGElement : public Noncopyable {
- static const bool value = true;
-};
-
-class SVGViewSpec;
-template<>
-struct IsDerivedFromSVGElement<SVGViewSpec> : public Noncopyable {
- static const bool value = false;
-};
-
// Helper template used for synchronizing SVG <-> XML properties
template<bool isDerivedFromSVGElement>
struct SVGAnimatedPropertySynchronizer {
diff --git a/WebCore/svg/properties/SVGListProperty.h b/WebCore/svg/properties/SVGListProperty.h
new file mode 100644
index 0000000..7edc0f1
--- /dev/null
+++ b/WebCore/svg/properties/SVGListProperty.h
@@ -0,0 +1,412 @@
+/*
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ *
+ * 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 SVGListProperty_h
+#define SVGListProperty_h
+
+#if ENABLE(SVG)
+#include "ExceptionCode.h"
+#include "SVGAnimatedProperty.h"
+#include "SVGPropertyTearOff.h"
+#include "SVGPropertyTraits.h"
+
+namespace WebCore {
+
+template<typename PropertyType>
+class SVGAnimatedListPropertyTearOff;
+
+template<typename PropertyType>
+class SVGListProperty : public SVGProperty {
+public:
+ typedef SVGListProperty<PropertyType> Self;
+
+ typedef typename SVGPropertyTraits<PropertyType>::ListItemType ListItemType;
+ typedef SVGPropertyTearOff<ListItemType> ListItemTearOff;
+ typedef PassRefPtr<ListItemTearOff> PassListItemTearOff;
+ typedef SVGAnimatedListPropertyTearOff<PropertyType> AnimatedListPropertyTearOff;
+ typedef typename SVGAnimatedListPropertyTearOff<PropertyType>::ListWrapperCache ListWrapperCache;
+
+ bool canAlterList(ExceptionCode& ec) const
+ {
+ if (m_role == AnimValRole) {
+ ec = NO_MODIFICATION_ALLOWED_ERR;
+ return false;
+ }
+
+ return true;
+ }
+
+ // SVGList::clear()
+ void clearValues(PropertyType& values, ExceptionCode& ec)
+ {
+ if (!canAlterList(ec))
+ return;
+
+ values.clear();
+ commitChange();
+ }
+
+ void clearValuesAndWrappers(AnimatedListPropertyTearOff* animatedList, ExceptionCode& ec)
+ {
+ ASSERT(animatedList);
+ if (!canAlterList(ec))
+ return;
+
+ animatedList->detachListWrappers(0);
+ animatedList->values().clear();
+ commitChange();
+ }
+
+ // SVGList::numberOfItems()
+ unsigned numberOfItemsValues(PropertyType& values) const
+ {
+ return values.size();
+ }
+
+ unsigned numberOfItemsValuesAndWrappers(AnimatedListPropertyTearOff* animatedList) const
+ {
+ ASSERT(animatedList);
+ return animatedList->values().size();
+ }
+
+ // SVGList::initialize()
+ ListItemType initializeValues(PropertyType& values, const ListItemType& newItem, ExceptionCode& ec)
+ {
+ if (!canAlterList(ec))
+ return ListItemType();
+
+ // Spec: If the inserted item is already in a list, it is removed from its previous list before it is inserted into this list.
+ processIncomingListItemValue(newItem, 0);
+
+ // Spec: Clears all existing current items from the list and re-initializes the list to hold the single item specified by the parameter.
+ values.clear();
+ values.append(newItem);
+
+ commitChange();
+ return newItem;
+ }
+
+ PassListItemTearOff initializeValuesAndWrappers(AnimatedListPropertyTearOff* animatedList, PassListItemTearOff passNewItem, ExceptionCode& ec)
+ {
+ ASSERT(animatedList);
+ if (!canAlterList(ec))
+ return 0;
+
+ // Not specified, but FF/Opera do it this way, and it's just sane.
+ if (!passNewItem) {
+ ec = TYPE_MISMATCH_ERR;
+ return 0;
+ }
+
+ PropertyType& values = animatedList->values();
+ ListWrapperCache& wrappers = animatedList->wrappers();
+
+ RefPtr<ListItemTearOff> newItem = passNewItem;
+ ASSERT(values.size() == wrappers.size());
+
+ // Spec: If the inserted item is already in a list, it is removed from its previous list before it is inserted into this list.
+ processIncomingListItemWrapper(newItem, 0);
+
+ // Spec: Clears all existing current items from the list and re-initializes the list to hold the single item specified by the parameter.
+ animatedList->detachListWrappers(0);
+ values.clear();
+
+ values.append(newItem->propertyReference());
+ wrappers.append(newItem);
+
+ commitChange();
+ return newItem.release();
+ }
+
+ // SVGList::getItem()
+ bool canGetItem(PropertyType& values, unsigned index, ExceptionCode& ec)
+ {
+ if (index >= values.size()) {
+ ec = INDEX_SIZE_ERR;
+ return false;
+ }
+
+ return true;
+ }
+
+ ListItemType getItemValues(PropertyType& values, unsigned index, ExceptionCode& ec)
+ {
+ if (!canGetItem(values, index, ec))
+ return ListItemType();
+
+ // Spec: Returns the specified item from the list. The returned item is the item itself and not a copy.
+ return values.at(index);
+ }
+
+ PassListItemTearOff getItemValuesAndWrappers(AnimatedListPropertyTearOff* animatedList, unsigned index, ExceptionCode& ec)
+ {
+ ASSERT(animatedList);
+ PropertyType& values = animatedList->values();
+ if (!canGetItem(values, index, ec))
+ return 0;
+
+ ListWrapperCache& wrappers = animatedList->wrappers();
+
+ // Spec: Returns the specified item from the list. The returned item is the item itself and not a copy.
+ // Any changes made to the item are immediately reflected in the list.
+ ASSERT(values.size() == wrappers.size());
+ RefPtr<ListItemTearOff> wrapper = wrappers.at(index);
+ if (!wrapper) {
+ // Create new wrapper, which is allowed to directly modify the item in the list, w/o copying and cache the wrapper in our map.
+ // It is also associated with our animated property, so it can notify the SVG Element which holds the SVGAnimated*List
+ // that it has been modified (and thus can call svgAttributeChanged(associatedAttributeName)).
+ wrapper = ListItemTearOff::create(animatedList, UndefinedRole, values.at(index));
+ wrappers.at(index) = wrapper;
+ }
+
+ return wrapper.release();
+ }
+
+ // SVGList::insertItemBefore()
+ ListItemType insertItemBeforeValues(PropertyType& values, const ListItemType& newItem, unsigned index, ExceptionCode& ec)
+ {
+ if (!canAlterList(ec))
+ return ListItemType();
+
+ // Spec: If the index is greater than or equal to numberOfItems, then the new item is appended to the end of the list.
+ if (index > values.size())
+ index = values.size();
+
+ // Spec: If newItem is already in a list, it is removed from its previous list before it is inserted into this list.
+ processIncomingListItemValue(newItem, &index);
+
+ // Spec: Inserts a new item into the list at the specified position. The index of the item before which the new item is to be
+ // inserted. The first item is number 0. If the index is equal to 0, then the new item is inserted at the front of the list.
+ values.insert(index, newItem);
+
+ commitChange();
+ return newItem;
+ }
+
+ PassListItemTearOff insertItemBeforeValuesAndWrappers(AnimatedListPropertyTearOff* animatedList, PassListItemTearOff passNewItem, unsigned index, ExceptionCode& ec)
+ {
+ ASSERT(animatedList);
+ if (!canAlterList(ec))
+ return 0;
+
+ // Not specified, but FF/Opera do it this way, and it's just sane.
+ if (!passNewItem) {
+ ec = TYPE_MISMATCH_ERR;
+ return 0;
+ }
+
+ PropertyType& values = animatedList->values();
+ ListWrapperCache& wrappers = animatedList->wrappers();
+
+ // Spec: If the index is greater than or equal to numberOfItems, then the new item is appended to the end of the list.
+ if (index > values.size())
+ index = values.size();
+
+ RefPtr<ListItemTearOff> newItem = passNewItem;
+ ASSERT(values.size() == wrappers.size());
+
+ // Spec: If newItem is already in a list, it is removed from its previous list before it is inserted into this list.
+ processIncomingListItemWrapper(newItem, &index);
+
+ // Spec: Inserts a new item into the list at the specified position. The index of the item before which the new item is to be
+ // inserted. The first item is number 0. If the index is equal to 0, then the new item is inserted at the front of the list.
+ values.insert(index, newItem->propertyReference());
+
+ // Store new wrapper at position 'index', change its underlying value, so mutations of newItem, directly affect the item in the list.
+ wrappers.insert(index, newItem);
+
+ commitChange();
+ return newItem.release();
+ }
+
+ // SVGList::replaceItem()
+ bool canReplaceItem(PropertyType& values, unsigned index, ExceptionCode& ec)
+ {
+ if (!canAlterList(ec))
+ return false;
+
+ if (index >= values.size()) {
+ ec = INDEX_SIZE_ERR;
+ return false;
+ }
+
+ return true;
+ }
+
+ ListItemType replaceItemValues(PropertyType& values, const ListItemType& newItem, unsigned index, ExceptionCode& ec)
+ {
+ if (!canReplaceItem(values, index, ec))
+ return ListItemType();
+
+ // Spec: If newItem is already in a list, it is removed from its previous list before it is inserted into this list.
+ // Spec: If the item is already in this list, note that the index of the item to replace is before the removal of the item.
+ processIncomingListItemValue(newItem, &index);
+
+ // Update the value at the desired position 'index'.
+ values.at(index) = newItem;
+
+ commitChange();
+ return newItem;
+ }
+
+ PassListItemTearOff replaceItemValuesAndWrappers(AnimatedListPropertyTearOff* animatedList, PassListItemTearOff passNewItem, unsigned index, ExceptionCode& ec)
+ {
+ ASSERT(animatedList);
+ PropertyType& values = animatedList->values();
+ if (!canReplaceItem(values, index, ec))
+ return 0;
+
+ // Not specified, but FF/Opera do it this way, and it's just sane.
+ if (!passNewItem) {
+ ec = TYPE_MISMATCH_ERR;
+ return 0;
+ }
+
+ ListWrapperCache& wrappers = animatedList->wrappers();
+ ASSERT(values.size() == wrappers.size());
+ RefPtr<ListItemTearOff> newItem = passNewItem;
+
+ // Spec: If newItem is already in a list, it is removed from its previous list before it is inserted into this list.
+ // Spec: If the item is already in this list, note that the index of the item to replace is before the removal of the item.
+ processIncomingListItemWrapper(newItem, &index);
+
+ // Detach the existing wrapper.
+ RefPtr<ListItemTearOff>& oldItem = wrappers.at(index);
+ if (oldItem)
+ oldItem->detachWrapper();
+
+ // Update the value and the wrapper at the desired position 'index'.
+ values.at(index) = newItem->propertyReference();
+ wrappers.at(index) = newItem;
+
+ commitChange();
+ return newItem.release();
+ }
+
+ // SVGList::removeItem()
+ bool canRemoveItem(PropertyType& values, unsigned index, ExceptionCode& ec)
+ {
+ if (!canAlterList(ec))
+ return false;
+
+ if (index >= values.size()) {
+ ec = INDEX_SIZE_ERR;
+ return false;
+ }
+
+ return true;
+ }
+
+ ListItemType removeItemValues(PropertyType& values, unsigned index, ExceptionCode& ec)
+ {
+ if (!canRemoveItem(values, index, ec))
+ return ListItemType();
+
+ ListItemType oldItem = values.at(index);
+ values.remove(index);
+
+ commitChange();
+ return oldItem;
+ }
+
+ PassListItemTearOff removeItemValuesAndWrappers(AnimatedListPropertyTearOff* animatedList, unsigned index, ExceptionCode& ec)
+ {
+ ASSERT(animatedList);
+ PropertyType& values = animatedList->values();
+ if (!canRemoveItem(values, index, ec))
+ return 0;
+
+ ListWrapperCache& wrappers = animatedList->wrappers();
+ ASSERT(values.size() == wrappers.size());
+
+ // Detach the existing wrapper.
+ RefPtr<ListItemTearOff>& oldItem = wrappers.at(index);
+ if (oldItem)
+ oldItem->detachWrapper();
+
+ wrappers.remove(index);
+ values.remove(index);
+
+ commitChange();
+ return oldItem.release();
+ }
+
+ // SVGList::appendItem()
+ ListItemType appendItemValues(PropertyType& values, const ListItemType& newItem, ExceptionCode& ec)
+ {
+ if (!canAlterList(ec))
+ return ListItemType();
+
+ // Spec: If newItem is already in a list, it is removed from its previous list before it is inserted into this list.
+ processIncomingListItemValue(newItem, 0);
+
+ // Append the value at the end of the list.
+ values.append(newItem);
+
+ commitChange();
+ return newItem;
+ }
+
+ PassListItemTearOff appendItemValuesAndWrappers(AnimatedListPropertyTearOff* animatedList, PassListItemTearOff passNewItem, ExceptionCode& ec)
+ {
+ ASSERT(animatedList);
+ if (!canAlterList(ec))
+ return 0;
+
+ // Not specified, but FF/Opera do it this way, and it's just sane.
+ if (!passNewItem) {
+ ec = TYPE_MISMATCH_ERR;
+ return 0;
+ }
+
+ PropertyType& values = animatedList->values();
+ ListWrapperCache& wrappers = animatedList->wrappers();
+
+ RefPtr<ListItemTearOff> newItem = passNewItem;
+ ASSERT(values.size() == wrappers.size());
+
+ // Spec: If newItem is already in a list, it is removed from its previous list before it is inserted into this list.
+ processIncomingListItemWrapper(newItem, 0);
+
+ // Append the value and wrapper at the end of the list.
+ values.append(newItem->propertyReference());
+ wrappers.append(newItem);
+
+ commitChange();
+ return newItem.release();
+ }
+
+protected:
+ SVGListProperty(SVGPropertyRole role)
+ : m_role(role)
+ {
+ }
+
+ virtual void commitChange() = 0;
+ virtual void processIncomingListItemValue(const ListItemType& newItem, unsigned* indexToModify) = 0;
+ virtual void processIncomingListItemWrapper(RefPtr<ListItemTearOff>& newItem, unsigned* indexToModify) = 0;
+
+private:
+ SVGPropertyRole m_role;
+};
+
+}
+
+#endif // ENABLE(SVG)
+#endif // SVGListProperty_h
diff --git a/WebCore/svg/properties/SVGListPropertyTearOff.h b/WebCore/svg/properties/SVGListPropertyTearOff.h
index 2801168..56d626f 100644
--- a/WebCore/svg/properties/SVGListPropertyTearOff.h
+++ b/WebCore/svg/properties/SVGListPropertyTearOff.h
@@ -21,52 +21,43 @@
#define SVGListPropertyTearOff_h
#if ENABLE(SVG)
-#include "ExceptionCode.h"
-#include "SVGAnimatedProperty.h"
-#include "SVGPropertyTearOff.h"
-#include "SVGPropertyTraits.h"
+#include "SVGListProperty.h"
namespace WebCore {
template<typename PropertyType>
-class SVGAnimatedListPropertyTearOff;
-
-template<typename PropertyType>
-class SVGListPropertyTearOff : public SVGProperty {
+class SVGListPropertyTearOff : public SVGListProperty<PropertyType> {
public:
- typedef SVGListPropertyTearOff<PropertyType> Self;
+ typedef SVGListProperty<PropertyType> Base;
typedef typename SVGPropertyTraits<PropertyType>::ListItemType ListItemType;
typedef SVGPropertyTearOff<ListItemType> ListItemTearOff;
typedef PassRefPtr<ListItemTearOff> PassListItemTearOff;
- typedef Vector<RefPtr<ListItemTearOff> > ListWrapperCache;
+ typedef SVGAnimatedListPropertyTearOff<PropertyType> AnimatedListPropertyTearOff;
+ typedef typename SVGAnimatedListPropertyTearOff<PropertyType>::ListWrapperCache ListWrapperCache;
- // Used for [SVGAnimatedProperty] types (for example: SVGAnimatedLengthList::baseVal())
- static PassRefPtr<Self> create(SVGAnimatedProperty* animatedProperty, SVGPropertyRole role, PropertyType& values)
+ static PassRefPtr<SVGListPropertyTearOff<PropertyType> > create(AnimatedListPropertyTearOff* animatedProperty, SVGPropertyRole role)
{
ASSERT(animatedProperty);
- return adoptRef(new Self(animatedProperty, role, values));
- }
-
- // Used for non-animated POD types (for example: SVGStringList).
- static PassRefPtr<Self> create(const PropertyType& initialValue)
- {
- return adoptRef(new Self(initialValue));
+ return adoptRef(new SVGListPropertyTearOff<PropertyType>(animatedProperty, role));
}
int removeItemFromList(ListItemTearOff* removeItem, bool shouldSynchronizeWrappers)
{
+ PropertyType& values = m_animatedProperty->values();
+ ListWrapperCache& wrappers = m_animatedProperty->wrappers();
+
// Lookup item in cache and remove its corresponding wrapper.
- unsigned size = m_wrappers.size();
- ASSERT(size == m_values->size());
+ unsigned size = wrappers.size();
+ ASSERT(size == values.size());
for (unsigned i = 0; i < size; ++i) {
- RefPtr<ListItemTearOff>& item = m_wrappers.at(i);
+ RefPtr<ListItemTearOff>& item = wrappers.at(i);
if (item != removeItem)
continue;
item->detachWrapper();
- m_wrappers.remove(i);
- m_values->remove(i);
+ wrappers.remove(i);
+ values.remove(i);
if (shouldSynchronizeWrappers)
commitChange();
@@ -77,275 +68,103 @@ public:
return -1;
}
- void detachListWrappers(unsigned newListSize)
- {
- // See SVGPropertyTearOff::detachWrapper() for an explaination what's happening here.
- unsigned size = m_wrappers.size();
- ASSERT(size == m_values->size());
- for (unsigned i = 0; i < size; ++i) {
- RefPtr<ListItemTearOff>& item = m_wrappers.at(i);
- if (!item)
- continue;
- item->detachWrapper();
- }
-
- // Reinitialize the wrapper cache to be equal to the new values size, after the XML DOM changed the list.
- if (newListSize)
- m_wrappers.fill(0, newListSize);
- else
- m_wrappers.clear();
- }
-
// SVGList API
void clear(ExceptionCode& ec)
{
- if (m_role == AnimValRole) {
- ec = NO_MODIFICATION_ALLOWED_ERR;
- return;
- }
-
- detachListWrappers(0);
- m_values->clear();
+ Base::clearValuesAndWrappers(m_animatedProperty.get(), ec);
}
unsigned numberOfItems() const
{
- return m_values->size();
+ return Base::numberOfItemsValuesAndWrappers(m_animatedProperty.get());
}
PassListItemTearOff initialize(PassListItemTearOff passNewItem, ExceptionCode& ec)
{
- if (m_role == AnimValRole) {
- ec = NO_MODIFICATION_ALLOWED_ERR;
- return 0;
- }
-
- // Not specified, but FF/Opera do it this way, and it's just sane.
- if (!passNewItem) {
- ec = TYPE_MISMATCH_ERR;
- return 0;
- }
-
- RefPtr<ListItemTearOff> newItem = passNewItem;
- ASSERT(m_values->size() == m_wrappers.size());
-
- // Spec: If the inserted item is already in a list, it is removed from its previous list before it is inserted into this list.
- removeItemFromListIfNeeded(newItem.get(), 0);
-
- // Spec: Clears all existing current items from the list and re-initializes the list to hold the single item specified by the parameter.
- detachListWrappers(0);
- m_values->clear();
-
- m_values->append(newItem->propertyReference());
- m_wrappers.append(newItem);
-
- commitChange();
- return newItem.release();
+ return Base::initializeValuesAndWrappers(m_animatedProperty.get(), passNewItem, ec);
}
PassListItemTearOff getItem(unsigned index, ExceptionCode& ec)
{
- if (index >= m_values->size()) {
- ec = INDEX_SIZE_ERR;
- return 0;
- }
-
- // Spec: Returns the specified item from the list. The returned item is the item itself and not a copy.
- // Any changes made to the item are immediately reflected in the list.
- ASSERT(m_values->size() == m_wrappers.size());
- RefPtr<ListItemTearOff> wrapper = m_wrappers.at(index);
- if (!wrapper) {
- // Create new wrapper, which is allowed to directly modify the item in the list, w/o copying and cache the wrapper in our map.
- // It is also associated with our animated property, so it can notify the SVG Element which holds the SVGAnimated*List
- // that it has been modified (and thus can call svgAttributeChanged(associatedAttributeName)).
- wrapper = ListItemTearOff::create(m_animatedProperty.get(), UndefinedRole, m_values->at(index));
- m_wrappers.at(index) = wrapper;
- }
-
- return wrapper.release();
+ return Base::getItemValuesAndWrappers(m_animatedProperty.get(), index, ec);
}
PassListItemTearOff insertItemBefore(PassListItemTearOff passNewItem, unsigned index, ExceptionCode& ec)
{
- if (m_role == AnimValRole) {
- ec = NO_MODIFICATION_ALLOWED_ERR;
- return 0;
- }
-
- // Not specified, but FF/Opera do it this way, and it's just sane.
- if (!passNewItem) {
- ec = TYPE_MISMATCH_ERR;
- return 0;
- }
-
- // Spec: If the index is greater than or equal to numberOfItems, then the new item is appended to the end of the list.
- if (index > m_values->size())
- index = m_values->size();
-
- RefPtr<ListItemTearOff> newItem = passNewItem;
- ASSERT(m_values->size() == m_wrappers.size());
-
- // Spec: If newItem is already in a list, it is removed from its previous list before it is inserted into this list.
- removeItemFromListIfNeeded(newItem.get(), &index);
-
- // Spec: Inserts a new item into the list at the specified position. The index of the item before which the new item is to be
- // inserted. The first item is number 0. If the index is equal to 0, then the new item is inserted at the front of the list.
- m_values->insert(index, newItem->propertyReference());
-
- // Store new wrapper at position 'index', change its underlying value, so mutations of newItem, directly affect the item in the list.
- m_wrappers.insert(index, newItem);
-
- commitChange();
- return newItem.release();
+ return Base::insertItemBeforeValuesAndWrappers(m_animatedProperty.get(), passNewItem, index, ec);
}
PassListItemTearOff replaceItem(PassListItemTearOff passNewItem, unsigned index, ExceptionCode& ec)
{
- if (m_role == AnimValRole) {
- ec = NO_MODIFICATION_ALLOWED_ERR;
- return 0;
- }
-
- if (index >= m_values->size()) {
- ec = INDEX_SIZE_ERR;
- return 0;
- }
-
- // Not specified, but FF/Opera do it this way, and it's just sane.
- if (!passNewItem) {
- ec = TYPE_MISMATCH_ERR;
- return 0;
- }
-
- RefPtr<ListItemTearOff> newItem = passNewItem;
- ASSERT(m_values->size() == m_wrappers.size());
-
- // Spec: If newItem is already in a list, it is removed from its previous list before it is inserted into this list.
- // Spec: If the item is already in this list, note that the index of the item to replace is before the removal of the item.
- removeItemFromListIfNeeded(newItem.get(), &index);
-
- // Detach the existing wrapper.
- RefPtr<ListItemTearOff>& oldItem = m_wrappers.at(index);
- if (oldItem)
- oldItem->detachWrapper();
-
- // Update the value and the wrapper at the desired position 'index'.
- m_values->at(index) = newItem->propertyReference();
- m_wrappers.at(index) = newItem;
-
- commitChange();
- return newItem.release();
+ return Base::replaceItemValuesAndWrappers(m_animatedProperty.get(), passNewItem, index, ec);
}
PassListItemTearOff removeItem(unsigned index, ExceptionCode& ec)
{
- if (m_role == AnimValRole) {
- ec = NO_MODIFICATION_ALLOWED_ERR;
- return 0;
- }
-
- if (index >= m_values->size()) {
- ec = INDEX_SIZE_ERR;
- return 0;
- }
-
- ASSERT(m_values->size() == m_wrappers.size());
-
- // Detach the existing wrapper.
- RefPtr<ListItemTearOff>& oldItem = m_wrappers.at(index);
- if (oldItem) {
- oldItem->detachWrapper();
- m_wrappers.remove(index);
- }
-
- m_values->remove(index);
-
- commitChange();
- return oldItem.release();
+ return Base::removeItemValuesAndWrappers(m_animatedProperty.get(), index, ec);
}
PassListItemTearOff appendItem(PassListItemTearOff passNewItem, ExceptionCode& ec)
{
- if (m_role == AnimValRole) {
- ec = NO_MODIFICATION_ALLOWED_ERR;
- return 0;
- }
-
- // Not specified, but FF/Opera do it this way, and it's just sane.
- if (!passNewItem) {
- ec = TYPE_MISMATCH_ERR;
- return 0;
- }
-
- RefPtr<ListItemTearOff> newItem = passNewItem;
- ASSERT(m_values->size() == m_wrappers.size());
-
- // Spec: If newItem is already in a list, it is removed from its previous list before it is inserted into this list.
- removeItemFromListIfNeeded(newItem.get(), 0);
-
- // Append the value and wrapper at the end of the list.
- m_values->append(newItem->propertyReference());
- m_wrappers.append(newItem);
-
- commitChange();
- return newItem.release();
+ return Base::appendItemValuesAndWrappers(m_animatedProperty.get(), passNewItem, ec);
}
private:
- SVGListPropertyTearOff(SVGAnimatedProperty* animatedProperty, SVGPropertyRole role, PropertyType& values)
- : m_animatedProperty(animatedProperty)
- , m_role(role)
- , m_values(&values)
- , m_valuesIsCopy(false)
- {
- // Using operator & is completly fine, as SVGAnimatedProperty owns this reference,
- // and we're guaranteed to live as long as SVGAnimatedProperty does.
- if (!values.isEmpty())
- m_wrappers.fill(0, values.size());
- }
-
- SVGListPropertyTearOff(const PropertyType& initialValue)
- : m_animatedProperty(0)
- , m_role(UndefinedRole)
- , m_values(new PropertyType(initialValue))
- , m_valuesIsCopy(true)
+ SVGListPropertyTearOff(AnimatedListPropertyTearOff* animatedProperty, SVGPropertyRole role)
+ : SVGListProperty<PropertyType>(role)
+ , m_animatedProperty(animatedProperty)
{
}
- virtual ~SVGListPropertyTearOff()
+ virtual void commitChange()
{
- if (m_valuesIsCopy)
- delete m_values;
- }
+ PropertyType& values = m_animatedProperty->values();
+ ListWrapperCache& wrappers = m_animatedProperty->wrappers();
- void commitChange()
- {
- // Update existing wrappers, as the index in the m_values list has changed.
- unsigned size = m_wrappers.size();
- ASSERT(size == m_values->size());
+ // Update existing wrappers, as the index in the values list has changed.
+ unsigned size = wrappers.size();
+ ASSERT(size == values.size());
for (unsigned i = 0; i < size; ++i) {
- RefPtr<ListItemTearOff>& item = m_wrappers.at(i);
+ RefPtr<ListItemTearOff>& item = wrappers.at(i);
if (!item)
continue;
item->setAnimatedProperty(m_animatedProperty.get());
- item->setValue(m_values->at(i));
+ item->setValue(values.at(i));
}
- ASSERT(!m_valuesIsCopy);
- ASSERT(m_animatedProperty);
m_animatedProperty->commitChange();
}
- void removeItemFromListIfNeeded(ListItemTearOff* newItem, unsigned* indexToModify)
+ virtual void processIncomingListItemValue(const ListItemType&, unsigned*)
+ {
+ ASSERT_NOT_REACHED();
+ }
+
+ virtual void processIncomingListItemWrapper(RefPtr<ListItemTearOff>& newItem, unsigned* indexToModify)
{
- // Spec: If newItem is already in a list, it is removed from its previous list before it is inserted into this list.
SVGAnimatedProperty* animatedPropertyOfItem = newItem->animatedProperty();
- if (!animatedPropertyOfItem || !animatedPropertyOfItem->isAnimatedListTearOff())
+
+ // newItem has been created manually, it doesn't belong to any SVGElement.
+ // (for example: "textElement.x.baseVal.appendItem(svgsvgElement.createSVGLength())")
+ if (!animatedPropertyOfItem)
+ return;
+
+ // newItem belongs to a SVGElement, but its associated SVGAnimatedProperty is not an animated list tear off.
+ // (for example: "textElement.x.baseVal.appendItem(rectElement.width.baseVal)")
+ if (!animatedPropertyOfItem->isAnimatedListTearOff()) {
+ // We have to copy the incoming newItem, as we're not allowed to insert this tear off as is into our wrapper cache.
+ // Otherwhise we'll end up having two SVGAnimatedPropertys that operate on the same SVGPropertyTearOff. Consider the example above:
+ // SVGRectElements SVGAnimatedLength 'width' property baseVal points to the same tear off object
+ // that's inserted into SVGTextElements SVGAnimatedLengthList 'x'. textElement.x.baseVal.getItem(0).value += 150 would
+ // mutate the rectElement width _and_ the textElement x list. That's obviously wrong, take care of that.
+ newItem = ListItemTearOff::create(newItem->propertyReference());
return;
+ }
+ // Spec: If newItem is already in a list, it is removed from its previous list before it is inserted into this list.
// 'newItem' is already living in another list. If it's not our list, synchronize the other lists wrappers after the removal.
bool livesInOtherList = animatedPropertyOfItem != m_animatedProperty;
- int removedIndex = static_cast<SVGAnimatedListPropertyTearOff<PropertyType>*>(animatedPropertyOfItem)->removeItemFromList(newItem, livesInOtherList);
+ int removedIndex = static_cast<AnimatedListPropertyTearOff*>(animatedPropertyOfItem)->removeItemFromList(newItem.get(), livesInOtherList);
ASSERT(removedIndex != -1);
if (!indexToModify)
@@ -363,17 +182,7 @@ private:
private:
// Back pointer to the animated property that created us
// For example (text.x.baseVal): m_animatedProperty points to the 'x' SVGAnimatedLengthList object
- RefPtr<SVGAnimatedProperty> m_animatedProperty;
-
- // The role of this property (baseVal or animVal)
- SVGPropertyRole m_role;
-
- // For the example above (text.x.baseVal): A reference to the SVGLengthList& stored in the SVGTextElement, which we can directly modify
- PropertyType* m_values;
- bool m_valuesIsCopy : 1;
-
- // A list of wrappers, which is always in sync between m_values.
- ListWrapperCache m_wrappers;
+ RefPtr<AnimatedListPropertyTearOff> m_animatedProperty;
};
}
diff --git a/WebCore/svg/properties/SVGPropertyTearOff.h b/WebCore/svg/properties/SVGPropertyTearOff.h
index 17588b4..2ffaede 100644
--- a/WebCore/svg/properties/SVGPropertyTearOff.h
+++ b/WebCore/svg/properties/SVGPropertyTearOff.h
@@ -32,7 +32,7 @@ class SVGPropertyTearOff : public SVGProperty {
public:
typedef SVGPropertyTearOff<PropertyType> Self;
- // Used for [SVGAnimatedProperty] types (for example: SVGAnimatedLength::baseVal()).
+ // Used for child types (baseVal/animVal) of a SVGAnimated* property (for example: SVGAnimatedLength::baseVal()).
// Also used for list tear offs (for example: text.x.baseVal.getItem(0)).
static PassRefPtr<Self> create(SVGAnimatedProperty* animatedProperty, SVGPropertyRole, PropertyType& value)
{
@@ -40,7 +40,7 @@ public:
return adoptRef(new Self(animatedProperty, value));
}
- // Used for non-animated POD types (for example: SVGLength).
+ // Used for non-animated POD types (for example: SVGSVGElement::createSVGLength()).
static PassRefPtr<Self> create(const PropertyType& initialValue)
{
return adoptRef(new Self(initialValue));
@@ -49,8 +49,6 @@ public:
PropertyType& propertyReference() { return *m_value; }
SVGAnimatedProperty* animatedProperty() const { return m_animatedProperty.get(); }
- virtual int removeItemFromList(SVGAnimatedProperty*) { return -1; }
-
// Used only by the list tear offs!
void setValue(PropertyType& value)
{
@@ -81,16 +79,17 @@ public:
ASSERT(!m_valueIsCopy);
m_value = new PropertyType(*m_value);
m_valueIsCopy = true;
+ m_animatedProperty = 0;
}
- void commitChange()
+ virtual void commitChange()
{
if (!m_animatedProperty || m_valueIsCopy)
return;
m_animatedProperty->commitChange();
}
-private:
+protected:
SVGPropertyTearOff(SVGAnimatedProperty* animatedProperty, PropertyType& value)
: m_animatedProperty(animatedProperty)
, m_value(&value)
diff --git a/WebCore/svg/properties/SVGPropertyTraits.h b/WebCore/svg/properties/SVGPropertyTraits.h
index 8d82a61..85bca7e 100644
--- a/WebCore/svg/properties/SVGPropertyTraits.h
+++ b/WebCore/svg/properties/SVGPropertyTraits.h
@@ -26,7 +26,10 @@
#include "SVGAngle.h"
#include "SVGLength.h"
#include "SVGLengthList.h"
+#include "SVGNumberList.h"
+#include "SVGPointList.h"
#include "SVGPreserveAspectRatio.h"
+#include "SVGStringList.h"
#include <wtf/text/StringBuilder.h>
namespace WebCore {
@@ -79,6 +82,14 @@ struct SVGPropertyTraits<float> {
};
template<>
+struct SVGPropertyTraits<SVGNumberList> {
+ typedef float ListItemType;
+
+ static SVGNumberList initialValue() { return SVGNumberList(); }
+ static String toString(const SVGNumberList& type) { return type.valueAsString(); }
+};
+
+template<>
struct SVGPropertyTraits<SVGPreserveAspectRatio> {
static SVGPreserveAspectRatio initialValue() { return SVGPreserveAspectRatio(); }
static String toString(const SVGPreserveAspectRatio& type) { return type.valueAsString(); }
@@ -108,6 +119,17 @@ struct SVGPropertyTraits<String> {
static String toString(const String& type) { return type; }
};
+template<>
+struct SVGPropertyTraits<SVGStringList> {
+ typedef String ListItemType;
+};
+
+template<>
+struct SVGPropertyTraits<SVGPointList> {
+ static SVGPointList initialValue() { return SVGPointList(); }
+ typedef FloatPoint ListItemType;
+};
+
}
#endif
diff --git a/WebCore/svg/properties/SVGStaticListPropertyTearOff.h b/WebCore/svg/properties/SVGStaticListPropertyTearOff.h
new file mode 100644
index 0000000..a6f0f28
--- /dev/null
+++ b/WebCore/svg/properties/SVGStaticListPropertyTearOff.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ *
+ * 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 SVGStaticListPropertyTearOff_h
+#define SVGStaticListPropertyTearOff_h
+
+#if ENABLE(SVG)
+#include "SVGListProperty.h"
+
+namespace WebCore {
+
+template<typename PropertyType>
+class SVGStaticListPropertyTearOff : public SVGListProperty<PropertyType> {
+public:
+ typedef SVGListProperty<PropertyType> Base;
+
+ typedef typename SVGPropertyTraits<PropertyType>::ListItemType ListItemType;
+ typedef SVGPropertyTearOff<ListItemType> ListItemTearOff;
+
+ static PassRefPtr<SVGStaticListPropertyTearOff<PropertyType> > create(SVGElement* contextElement, PropertyType& values)
+ {
+ ASSERT(contextElement);
+ return adoptRef(new SVGStaticListPropertyTearOff<PropertyType>(contextElement, values));
+ }
+
+ // SVGList API
+ void clear(ExceptionCode& ec)
+ {
+ Base::clearValues(m_values, ec);
+ }
+
+ unsigned numberOfItems() const
+ {
+ return Base::numberOfItemsValues(m_values);
+ }
+
+ ListItemType initialize(const ListItemType& newItem, ExceptionCode& ec)
+ {
+ return Base::initializeValues(m_values, newItem, ec);
+ }
+
+ ListItemType getItem(unsigned index, ExceptionCode& ec)
+ {
+ return Base::getItemValues(m_values, index, ec);
+ }
+
+ ListItemType insertItemBefore(const ListItemType& newItem, unsigned index, ExceptionCode& ec)
+ {
+ return Base::insertItemBeforeValues(m_values, newItem, index, ec);
+ }
+
+ ListItemType replaceItem(const ListItemType& newItem, unsigned index, ExceptionCode& ec)
+ {
+ return Base::replaceItemValues(m_values, newItem, index, ec);
+ }
+
+ ListItemType removeItem(unsigned index, ExceptionCode& ec)
+ {
+ return Base::removeItemValues(m_values, index, ec);
+ }
+
+ ListItemType appendItem(const ListItemType& newItem, ExceptionCode& ec)
+ {
+ return Base::appendItemValues(m_values, newItem, ec);
+ }
+
+private:
+ SVGStaticListPropertyTearOff(SVGElement* contextElement, PropertyType& values)
+ : SVGListProperty<PropertyType>(UndefinedRole)
+ , m_contextElement(contextElement)
+ , m_values(values)
+ {
+ }
+
+ virtual void commitChange()
+ {
+ m_values.commitChange(m_contextElement.get());
+ }
+
+ virtual void processIncomingListItemValue(const ListItemType&, unsigned*)
+ {
+ // no-op for static lists
+ }
+
+ virtual void processIncomingListItemWrapper(RefPtr<ListItemTearOff>&, unsigned*)
+ {
+ ASSERT_NOT_REACHED();
+ }
+
+private:
+ RefPtr<SVGElement> m_contextElement;
+ PropertyType& m_values;
+};
+
+}
+
+#endif // ENABLE(SVG)
+#endif // SVGStaticListPropertyTearOff_h
diff --git a/WebCore/svg/properties/SVGStaticPropertyTearOff.h b/WebCore/svg/properties/SVGStaticPropertyTearOff.h
new file mode 100644
index 0000000..8f31909
--- /dev/null
+++ b/WebCore/svg/properties/SVGStaticPropertyTearOff.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ *
+ * 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 SVGStaticPropertyTearOff_h
+#define SVGStaticPropertyTearOff_h
+
+#if ENABLE(SVG)
+#include "SVGPropertyTearOff.h"
+
+namespace WebCore {
+
+#if COMPILER(MSVC)
+// UpdateMethod is 12 bytes. We have to pack to a size greater than or equal to that to avoid an
+// alignment warning (C4121). 16 is the next-largest size allowed for packing, so we use that.
+#pragma pack(push, 16)
+#endif
+template<typename ContextElement, typename PropertyType>
+class SVGStaticPropertyTearOff : public SVGPropertyTearOff<PropertyType> {
+public:
+ typedef SVGStaticPropertyTearOff<ContextElement, PropertyType> Self;
+ typedef void (ContextElement::*UpdateMethod)();
+
+ // Used for non-animated POD types that are not associated with a SVGAnimatedProperty object, nor with a XML DOM attribute
+ // (for example: SVGSVGElement::currentTranslate).
+ static PassRefPtr<Self> create(ContextElement* contextElement, PropertyType& value, UpdateMethod update)
+ {
+ ASSERT(contextElement);
+ return adoptRef(new Self(contextElement, value, update));
+ }
+
+ virtual void commitChange() { (m_contextElement.get()->*m_update)(); }
+
+private:
+ SVGStaticPropertyTearOff(ContextElement* contextElement, PropertyType& value, UpdateMethod update)
+ : SVGPropertyTearOff<PropertyType>(0, value)
+ , m_update(update)
+ , m_contextElement(contextElement)
+ {
+ }
+
+ UpdateMethod m_update;
+ RefPtr<ContextElement> m_contextElement;
+};
+#if COMPILER(MSVC)
+#pragma pack(pop)
+#endif
+
+}
+
+#endif // ENABLE(SVG)
+#endif // SVGStaticPropertyTearOff_h