1 /* 2 * Copyright (C) Research In Motion Limited 2010. All rights reserved. 3 * 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. 8 * 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. 13 * 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. 18 */ 19 20 #ifndef SVGListPropertyTearOff_h 21 #define SVGListPropertyTearOff_h 22 23 #if ENABLE(SVG) 24 #include "SVGListProperty.h" 25 26 namespace WebCore { 27 28 template<typename PropertyType> 29 class SVGListPropertyTearOff : public SVGListProperty<PropertyType> { 30 public: 31 typedef SVGListProperty<PropertyType> Base; 32 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; 38 create(AnimatedListPropertyTearOff * animatedProperty,SVGPropertyRole role)39 static PassRefPtr<SVGListPropertyTearOff<PropertyType> > create(AnimatedListPropertyTearOff* animatedProperty, SVGPropertyRole role) 40 { 41 ASSERT(animatedProperty); 42 return adoptRef(new SVGListPropertyTearOff<PropertyType>(animatedProperty, role)); 43 } 44 removeItemFromList(ListItemTearOff * removeItem,bool shouldSynchronizeWrappers)45 int removeItemFromList(ListItemTearOff* removeItem, bool shouldSynchronizeWrappers) 46 { 47 PropertyType& values = m_animatedProperty->values(); 48 ListWrapperCache& wrappers = m_animatedProperty->wrappers(); 49 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) 56 continue; 57 58 item->detachWrapper(); 59 wrappers.remove(i); 60 values.remove(i); 61 62 if (shouldSynchronizeWrappers) 63 commitChange(); 64 65 return i; 66 } 67 68 return -1; 69 } 70 71 // SVGList API clear(ExceptionCode & ec)72 void clear(ExceptionCode& ec) 73 { 74 Base::clearValuesAndWrappers(m_animatedProperty.get(), ec); 75 } 76 numberOfItems()77 unsigned numberOfItems() const 78 { 79 return Base::numberOfItemsValuesAndWrappers(m_animatedProperty.get()); 80 } 81 initialize(PassListItemTearOff passNewItem,ExceptionCode & ec)82 PassListItemTearOff initialize(PassListItemTearOff passNewItem, ExceptionCode& ec) 83 { 84 return Base::initializeValuesAndWrappers(m_animatedProperty.get(), passNewItem, ec); 85 } 86 getItem(unsigned index,ExceptionCode & ec)87 PassListItemTearOff getItem(unsigned index, ExceptionCode& ec) 88 { 89 return Base::getItemValuesAndWrappers(m_animatedProperty.get(), index, ec); 90 } 91 insertItemBefore(PassListItemTearOff passNewItem,unsigned index,ExceptionCode & ec)92 PassListItemTearOff insertItemBefore(PassListItemTearOff passNewItem, unsigned index, ExceptionCode& ec) 93 { 94 return Base::insertItemBeforeValuesAndWrappers(m_animatedProperty.get(), passNewItem, index, ec); 95 } 96 replaceItem(PassListItemTearOff passNewItem,unsigned index,ExceptionCode & ec)97 PassListItemTearOff replaceItem(PassListItemTearOff passNewItem, unsigned index, ExceptionCode& ec) 98 { 99 return Base::replaceItemValuesAndWrappers(m_animatedProperty.get(), passNewItem, index, ec); 100 } 101 removeItem(unsigned index,ExceptionCode & ec)102 PassListItemTearOff removeItem(unsigned index, ExceptionCode& ec) 103 { 104 return Base::removeItemValuesAndWrappers(m_animatedProperty.get(), index, ec); 105 } 106 appendItem(PassListItemTearOff passNewItem,ExceptionCode & ec)107 PassListItemTearOff appendItem(PassListItemTearOff passNewItem, ExceptionCode& ec) 108 { 109 return Base::appendItemValuesAndWrappers(m_animatedProperty.get(), passNewItem, ec); 110 } 111 112 protected: SVGListPropertyTearOff(AnimatedListPropertyTearOff * animatedProperty,SVGPropertyRole role)113 SVGListPropertyTearOff(AnimatedListPropertyTearOff* animatedProperty, SVGPropertyRole role) 114 : SVGListProperty<PropertyType>(role) 115 , m_animatedProperty(animatedProperty) 116 { 117 } 118 commitChange()119 virtual void commitChange() 120 { 121 PropertyType& values = m_animatedProperty->values(); 122 ListWrapperCache& wrappers = m_animatedProperty->wrappers(); 123 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); 129 if (!item) 130 continue; 131 item->setAnimatedProperty(m_animatedProperty.get()); 132 item->setValue(values.at(i)); 133 } 134 135 m_animatedProperty->commitChange(); 136 } 137 processIncomingListItemValue(const ListItemType &,unsigned *)138 virtual void processIncomingListItemValue(const ListItemType&, unsigned*) 139 { 140 ASSERT_NOT_REACHED(); 141 } 142 processIncomingListItemWrapper(RefPtr<ListItemTearOff> & newItem,unsigned * indexToModify)143 virtual void processIncomingListItemWrapper(RefPtr<ListItemTearOff>& newItem, unsigned* indexToModify) 144 { 145 SVGAnimatedProperty* animatedPropertyOfItem = newItem->animatedProperty(); 146 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) 150 return; 151 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()); 161 return; 162 } 163 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); 169 170 if (!indexToModify) 171 return; 172 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) 178 --index; 179 } 180 } 181 182 // Back pointer to the animated property that created us 183 // For example (text.x.baseVal): m_animatedProperty points to the 'x' SVGAnimatedLengthList object 184 RefPtr<AnimatedListPropertyTearOff> m_animatedProperty; 185 }; 186 187 } 188 189 #endif // ENABLE(SVG) 190 #endif // SVGListPropertyTearOff_h 191