summaryrefslogtreecommitdiffstats
path: root/WebCore/svg/properties/SVGListPropertyTearOff.h
diff options
context:
space:
mode:
authorTeng-Hui Zhu <ztenghui@google.com>2010-11-10 15:31:59 -0800
committerTeng-Hui Zhu <ztenghui@google.com>2010-11-17 13:35:59 -0800
commit28040489d744e0c5d475a88663056c9040ed5320 (patch)
treec463676791e4a63e452a95f0a12b2a8519730693 /WebCore/svg/properties/SVGListPropertyTearOff.h
parenteff9be92c41913c92fb1d3b7983c071f3e718678 (diff)
downloadexternal_webkit-28040489d744e0c5d475a88663056c9040ed5320.zip
external_webkit-28040489d744e0c5d475a88663056c9040ed5320.tar.gz
external_webkit-28040489d744e0c5d475a88663056c9040ed5320.tar.bz2
Merge WebKit at r71558: Initial merge by git.
Change-Id: Ib345578fa29df7e4bc72b4f00e4a6fddcb754c4c
Diffstat (limited to 'WebCore/svg/properties/SVGListPropertyTearOff.h')
-rw-r--r--WebCore/svg/properties/SVGListPropertyTearOff.h309
1 files changed, 59 insertions, 250 deletions
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;
};
}