2 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
20 #ifndef SVGListPropertyTearOff_h
21 #define SVGListPropertyTearOff_h
24 #include "SVGListProperty.h"
28 template<typename PropertyType>
29 class SVGListPropertyTearOff : public SVGListProperty<PropertyType> {
31 typedef SVGListProperty<PropertyType> Base;
33 typedef typename SVGPropertyTraits<PropertyType>::ListItemType ListItemType;
34 typedef SVGPropertyTearOff<ListItemType> ListItemTearOff;
35 typedef PassRefPtr<ListItemTearOff> PassListItemTearOff;
36 typedef SVGAnimatedListPropertyTearOff<PropertyType> AnimatedListPropertyTearOff;
37 typedef typename SVGAnimatedListPropertyTearOff<PropertyType>::ListWrapperCache ListWrapperCache;
39 static PassRefPtr<SVGListPropertyTearOff<PropertyType> > create(AnimatedListPropertyTearOff* animatedProperty, SVGPropertyRole role)
41 ASSERT(animatedProperty);
42 return adoptRef(new SVGListPropertyTearOff<PropertyType>(animatedProperty, role));
45 int removeItemFromList(ListItemTearOff* removeItem, bool shouldSynchronizeWrappers)
47 PropertyType& values = m_animatedProperty->values();
48 ListWrapperCache& wrappers = m_animatedProperty->wrappers();
50 // Lookup item in cache and remove its corresponding wrapper.
51 unsigned size = wrappers.size();
52 ASSERT(size == values.size());
53 for (unsigned i = 0; i < size; ++i) {
54 RefPtr<ListItemTearOff>& item = wrappers.at(i);
55 if (item != removeItem)
58 item->detachWrapper();
62 if (shouldSynchronizeWrappers)
72 void clear(ExceptionCode& ec)
74 Base::clearValuesAndWrappers(m_animatedProperty.get(), ec);
77 unsigned numberOfItems() const
79 return Base::numberOfItemsValuesAndWrappers(m_animatedProperty.get());
82 PassListItemTearOff initialize(PassListItemTearOff passNewItem, ExceptionCode& ec)
84 return Base::initializeValuesAndWrappers(m_animatedProperty.get(), passNewItem, ec);
87 PassListItemTearOff getItem(unsigned index, ExceptionCode& ec)
89 return Base::getItemValuesAndWrappers(m_animatedProperty.get(), index, ec);
92 PassListItemTearOff insertItemBefore(PassListItemTearOff passNewItem, unsigned index, ExceptionCode& ec)
94 return Base::insertItemBeforeValuesAndWrappers(m_animatedProperty.get(), passNewItem, index, ec);
97 PassListItemTearOff replaceItem(PassListItemTearOff passNewItem, unsigned index, ExceptionCode& ec)
99 return Base::replaceItemValuesAndWrappers(m_animatedProperty.get(), passNewItem, index, ec);
102 PassListItemTearOff removeItem(unsigned index, ExceptionCode& ec)
104 return Base::removeItemValuesAndWrappers(m_animatedProperty.get(), index, ec);
107 PassListItemTearOff appendItem(PassListItemTearOff passNewItem, ExceptionCode& ec)
109 return Base::appendItemValuesAndWrappers(m_animatedProperty.get(), passNewItem, ec);
113 SVGListPropertyTearOff(AnimatedListPropertyTearOff* animatedProperty, SVGPropertyRole role)
114 : SVGListProperty<PropertyType>(role)
115 , m_animatedProperty(animatedProperty)
119 virtual void commitChange()
121 PropertyType& values = m_animatedProperty->values();
122 ListWrapperCache& wrappers = m_animatedProperty->wrappers();
124 // Update existing wrappers, as the index in the values list has changed.
125 unsigned size = wrappers.size();
126 ASSERT(size == values.size());
127 for (unsigned i = 0; i < size; ++i) {
128 RefPtr<ListItemTearOff>& item = wrappers.at(i);
131 item->setAnimatedProperty(m_animatedProperty.get());
132 item->setValue(values.at(i));
135 m_animatedProperty->commitChange();
138 virtual void processIncomingListItemValue(const ListItemType&, unsigned*)
140 ASSERT_NOT_REACHED();
143 virtual void processIncomingListItemWrapper(RefPtr<ListItemTearOff>& newItem, unsigned* indexToModify)
145 SVGAnimatedProperty* animatedPropertyOfItem = newItem->animatedProperty();
147 // newItem has been created manually, it doesn't belong to any SVGElement.
148 // (for example: "textElement.x.baseVal.appendItem(svgsvgElement.createSVGLength())")
149 if (!animatedPropertyOfItem)
152 // newItem belongs to a SVGElement, but its associated SVGAnimatedProperty is not an animated list tear off.
153 // (for example: "textElement.x.baseVal.appendItem(rectElement.width.baseVal)")
154 if (!animatedPropertyOfItem->isAnimatedListTearOff()) {
155 // We have to copy the incoming newItem, as we're not allowed to insert this tear off as is into our wrapper cache.
156 // Otherwhise we'll end up having two SVGAnimatedPropertys that operate on the same SVGPropertyTearOff. Consider the example above:
157 // SVGRectElements SVGAnimatedLength 'width' property baseVal points to the same tear off object
158 // that's inserted into SVGTextElements SVGAnimatedLengthList 'x'. textElement.x.baseVal.getItem(0).value += 150 would
159 // mutate the rectElement width _and_ the textElement x list. That's obviously wrong, take care of that.
160 newItem = ListItemTearOff::create(newItem->propertyReference());
164 // Spec: If newItem is already in a list, it is removed from its previous list before it is inserted into this list.
165 // 'newItem' is already living in another list. If it's not our list, synchronize the other lists wrappers after the removal.
166 bool livesInOtherList = animatedPropertyOfItem != m_animatedProperty;
167 int removedIndex = static_cast<AnimatedListPropertyTearOff*>(animatedPropertyOfItem)->removeItemFromList(newItem.get(), livesInOtherList);
168 ASSERT(removedIndex != -1);
173 // If the item lived in our list, adjust the insertion index.
174 if (!livesInOtherList) {
175 unsigned& index = *indexToModify;
176 // Spec: If the item is already in this list, note that the index of the item to (replace|insert before) is before the removal of the item.
177 if (static_cast<unsigned>(removedIndex) < index)
183 // Back pointer to the animated property that created us
184 // For example (text.x.baseVal): m_animatedProperty points to the 'x' SVGAnimatedLengthList object
185 RefPtr<AnimatedListPropertyTearOff> m_animatedProperty;
190 #endif // ENABLE(SVG)
191 #endif // SVGListPropertyTearOff_h