diff options
author | Teng-Hui Zhu <ztenghui@google.com> | 2010-11-10 15:31:59 -0800 |
---|---|---|
committer | Teng-Hui Zhu <ztenghui@google.com> | 2010-11-17 13:35:59 -0800 |
commit | 28040489d744e0c5d475a88663056c9040ed5320 (patch) | |
tree | c463676791e4a63e452a95f0a12b2a8519730693 /WebCore/svg/properties/SVGListPropertyTearOff.h | |
parent | eff9be92c41913c92fb1d3b7983c071f3e718678 (diff) | |
download | external_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.h | 309 |
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; }; } |