#ifndef SVGListProperty_h
#define SVGListProperty_h
#if ENABLE(SVG)
#include "SVGAnimatedProperty.h"
#include "SVGException.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;
}
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();
}
unsigned numberOfItemsValues(PropertyType& values) const
{
return values.size();
}
unsigned numberOfItemsValuesAndWrappers(AnimatedListPropertyTearOff* animatedList) const
{
ASSERT(animatedList);
return animatedList->values().size();
}
ListItemType initializeValues(PropertyType& values, const ListItemType& newItem, ExceptionCode& ec)
{
if (!canAlterList(ec))
return ListItemType();
processIncomingListItemValue(newItem, 0);
values.clear();
values.append(newItem);
commitChange();
return newItem;
}
PassListItemTearOff initializeValuesAndWrappers(AnimatedListPropertyTearOff* animatedList, PassListItemTearOff passNewItem, ExceptionCode& ec)
{
ASSERT(animatedList);
if (!canAlterList(ec))
return 0;
if (!passNewItem) {
ec = SVGException::SVG_WRONG_TYPE_ERR;
return 0;
}
PropertyType& values = animatedList->values();
ListWrapperCache& wrappers = animatedList->wrappers();
RefPtr<ListItemTearOff> newItem = passNewItem;
ASSERT(values.size() == wrappers.size());
processIncomingListItemWrapper(newItem, 0);
animatedList->detachListWrappers(0);
values.clear();
values.append(newItem->propertyReference());
wrappers.append(newItem);
commitChange();
return newItem.release();
}
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();
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();
ASSERT(values.size() == wrappers.size());
RefPtr<ListItemTearOff> wrapper = wrappers.at(index);
if (!wrapper) {
wrapper = ListItemTearOff::create(animatedList, UndefinedRole, values.at(index));
wrappers.at(index) = wrapper;
}
return wrapper.release();
}
ListItemType insertItemBeforeValues(PropertyType& values, const ListItemType& newItem, unsigned index, ExceptionCode& ec)
{
if (!canAlterList(ec))
return ListItemType();
if (index > values.size())
index = values.size();
processIncomingListItemValue(newItem, &index);
values.insert(index, newItem);
commitChange();
return newItem;
}
PassListItemTearOff insertItemBeforeValuesAndWrappers(AnimatedListPropertyTearOff* animatedList, PassListItemTearOff passNewItem, unsigned index, ExceptionCode& ec)
{
ASSERT(animatedList);
if (!canAlterList(ec))
return 0;
if (!passNewItem) {
ec = SVGException::SVG_WRONG_TYPE_ERR;
return 0;
}
PropertyType& values = animatedList->values();
ListWrapperCache& wrappers = animatedList->wrappers();
if (index > values.size())
index = values.size();
RefPtr<ListItemTearOff> newItem = passNewItem;
ASSERT(values.size() == wrappers.size());
processIncomingListItemWrapper(newItem, &index);
values.insert(index, newItem->propertyReference());
wrappers.insert(index, newItem);
commitChange();
return newItem.release();
}
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();
processIncomingListItemValue(newItem, &index);
if (values.isEmpty()) {
ec = INDEX_SIZE_ERR;
return ListItemType();
}
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;
if (!passNewItem) {
ec = SVGException::SVG_WRONG_TYPE_ERR;
return 0;
}
ListWrapperCache& wrappers = animatedList->wrappers();
ASSERT(values.size() == wrappers.size());
RefPtr<ListItemTearOff> newItem = passNewItem;
processIncomingListItemWrapper(newItem, &index);
if (values.isEmpty()) {
ASSERT(wrappers.isEmpty());
ec = INDEX_SIZE_ERR;
return 0;
}
RefPtr<ListItemTearOff> oldItem = wrappers.at(index);
if (oldItem)
oldItem->detachWrapper();
values.at(index) = newItem->propertyReference();
wrappers.at(index) = newItem;
commitChange();
return newItem.release();
}
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());
RefPtr<ListItemTearOff> oldItem = wrappers.at(index);
if (!oldItem)
oldItem = ListItemTearOff::create(animatedList, UndefinedRole, values.at(index));
oldItem->detachWrapper();
wrappers.remove(index);
values.remove(index);
commitChange();
return oldItem.release();
}
ListItemType appendItemValues(PropertyType& values, const ListItemType& newItem, ExceptionCode& ec)
{
if (!canAlterList(ec))
return ListItemType();
processIncomingListItemValue(newItem, 0);
values.append(newItem);
commitChange();
return newItem;
}
PassListItemTearOff appendItemValuesAndWrappers(AnimatedListPropertyTearOff* animatedList, PassListItemTearOff passNewItem, ExceptionCode& ec)
{
ASSERT(animatedList);
if (!canAlterList(ec))
return 0;
if (!passNewItem) {
ec = SVGException::SVG_WRONG_TYPE_ERR;
return 0;
}
PropertyType& values = animatedList->values();
ListWrapperCache& wrappers = animatedList->wrappers();
RefPtr<ListItemTearOff> newItem = passNewItem;
ASSERT(values.size() == wrappers.size());
processIncomingListItemWrapper(newItem, 0);
values.append(newItem->propertyReference());
wrappers.append(newItem);
commitChange();
return newItem.release();
}
virtual SVGPropertyRole role() const { return m_role; }
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