2 * Copyright (C) 2013 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #ifndef NewSVGListPropertyHelper_h
32 #define NewSVGListPropertyHelper_h
34 #include "bindings/v8/ExceptionMessages.h"
35 #include "bindings/v8/ExceptionStatePlaceholder.h"
36 #include "core/dom/ExceptionCode.h"
37 #include "core/svg/properties/NewSVGProperty.h"
38 #include "wtf/PassRefPtr.h"
39 #include "wtf/Vector.h"
43 // This is an implementation of the SVG*List property spec:
44 // http://www.w3.org/TR/SVG/single-page.html#types-InterfaceSVGLengthList
45 template<typename Derived, typename ItemProperty>
46 class NewSVGListPropertyHelper : public NewSVGPropertyBase {
48 typedef ItemProperty ItemPropertyType;
50 NewSVGListPropertyHelper()
51 : NewSVGPropertyBase(Derived::classType())
55 ~NewSVGListPropertyHelper()
60 // used from Blink C++ code:
62 ItemPropertyType* at(size_t index)
64 ASSERT(index < m_values.size());
65 ASSERT(m_values.at(index)->ownerList() == this);
66 return m_values.at(index).get();
69 const ItemPropertyType* at(size_t index) const
71 return const_cast<NewSVGListPropertyHelper<Derived, ItemProperty>*>(this)->at(index);
76 typedef typename Vector<RefPtr<ItemPropertyType> >::const_iterator WrappedType;
79 ConstIterator(WrappedType it)
84 ConstIterator& operator++() { ++m_it; return *this; }
86 bool operator==(const ConstIterator& o) const { return m_it == o.m_it; }
87 bool operator!=(const ConstIterator& o) const { return m_it != o.m_it; }
89 PassRefPtr<ItemPropertyType> operator*() { return *m_it; }
90 PassRefPtr<ItemPropertyType> operator->() { return *m_it; }
96 ConstIterator begin() const
98 return ConstIterator(m_values.begin());
101 ConstIterator end() const
103 return ConstIterator(m_values.end());
106 void append(PassRefPtr<ItemPropertyType> passNewItem)
108 RefPtr<ItemPropertyType> newItem = passNewItem;
111 m_values.append(newItem);
112 newItem->setOwnerList(this);
115 bool operator==(const Derived&) const;
116 bool operator!=(const Derived& other) const
118 return !(*this == other);
123 return !numberOfItems();
126 // SVGList*Property DOM spec:
128 size_t numberOfItems() const
130 return m_values.size();
135 PassRefPtr<ItemPropertyType> initialize(PassRefPtr<ItemPropertyType>);
136 PassRefPtr<ItemPropertyType> getItem(size_t, ExceptionState&);
137 PassRefPtr<ItemPropertyType> insertItemBefore(PassRefPtr<ItemPropertyType>, size_t);
138 PassRefPtr<ItemPropertyType> removeItem(size_t, ExceptionState&);
139 PassRefPtr<ItemPropertyType> appendItem(PassRefPtr<ItemPropertyType>);
140 PassRefPtr<ItemPropertyType> replaceItem(PassRefPtr<ItemPropertyType>, size_t, ExceptionState&);
143 void deepCopy(PassRefPtr<Derived>);
146 inline bool checkIndexBound(size_t, ExceptionState&);
147 bool removeFromOldOwnerListAndAdjustIndex(PassRefPtr<ItemPropertyType>, size_t* indexToModify);
148 size_t findItem(PassRefPtr<ItemPropertyType>);
150 Vector<RefPtr<ItemPropertyType> > m_values;
152 static PassRefPtr<Derived> toDerived(PassRefPtr<NewSVGPropertyBase> passBase)
157 RefPtr<NewSVGPropertyBase> base = passBase;
158 ASSERT(base->type() == Derived::classType());
159 return static_pointer_cast<Derived>(base.release());
163 template<typename Derived, typename ItemProperty>
164 bool NewSVGListPropertyHelper<Derived, ItemProperty>::operator==(const Derived& other) const
166 if (numberOfItems() != other.numberOfItems())
169 size_t length = numberOfItems();
170 for (size_t i = 0; i < length; ++i) {
171 if (*at(i) != *other.at(i))
178 template<typename Derived, typename ItemProperty>
179 void NewSVGListPropertyHelper<Derived, ItemProperty>::clear()
181 // detach all list items as they are no longer part of this list
182 typename Vector<RefPtr<ItemPropertyType> >::const_iterator it = m_values.begin();
183 typename Vector<RefPtr<ItemPropertyType> >::const_iterator itEnd = m_values.end();
184 for (; it != itEnd; ++it) {
185 ASSERT((*it)->ownerList() == this);
186 (*it)->setOwnerList(0);
192 template<typename Derived, typename ItemProperty>
193 PassRefPtr<ItemProperty> NewSVGListPropertyHelper<Derived, ItemProperty>::initialize(PassRefPtr<ItemProperty> passNewItem)
195 RefPtr<ItemPropertyType> newItem = passNewItem;
197 // Spec: If the inserted item is already in a list, it is removed from its previous list before it is inserted into this list.
198 removeFromOldOwnerListAndAdjustIndex(newItem, 0);
200 // Spec: Clears all existing current items from the list and re-initializes the list to hold the single item specified by the parameter.
203 return newItem.release();
206 template<typename Derived, typename ItemProperty>
207 PassRefPtr<ItemProperty> NewSVGListPropertyHelper<Derived, ItemProperty>::getItem(size_t index, ExceptionState& exceptionState)
209 if (!checkIndexBound(index, exceptionState))
212 ASSERT(index < m_values.size());
213 ASSERT(m_values.at(index)->ownerList() == this);
214 return m_values.at(index);
217 template<typename Derived, typename ItemProperty>
218 PassRefPtr<ItemProperty> NewSVGListPropertyHelper<Derived, ItemProperty>::insertItemBefore(PassRefPtr<ItemProperty> passNewItem, size_t index)
220 // Spec: If the index is greater than or equal to numberOfItems, then the new item is appended to the end of the list.
221 if (index > m_values.size())
222 index = m_values.size();
224 RefPtr<ItemPropertyType> newItem = passNewItem;
226 // Spec: If newItem is already in a list, it is removed from its previous list before it is inserted into this list.
227 if (!removeFromOldOwnerListAndAdjustIndex(newItem, &index)) {
228 // Inserting the item before itself is a no-op.
229 return newItem.release();
232 // 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
233 // 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.
234 m_values.insert(index, newItem);
235 newItem->setOwnerList(this);
237 return newItem.release();
240 template<typename Derived, typename ItemProperty>
241 PassRefPtr<ItemProperty> NewSVGListPropertyHelper<Derived, ItemProperty>::removeItem(size_t index, ExceptionState& exceptionState)
243 if (index >= m_values.size()) {
244 exceptionState.throwDOMException(IndexSizeError, ExceptionMessages::indexExceedsMaximumBound("index", index, m_values.size()));
247 ASSERT(m_values.at(index)->ownerList() == this);
248 RefPtr<ItemPropertyType> oldItem = m_values.at(index);
249 m_values.remove(index);
250 oldItem->setOwnerList(0);
251 return oldItem.release();
254 template<typename Derived, typename ItemProperty>
255 PassRefPtr<ItemProperty> NewSVGListPropertyHelper<Derived, ItemProperty>::appendItem(PassRefPtr<ItemProperty> passNewItem)
257 RefPtr<ItemPropertyType> newItem = passNewItem;
259 // Spec: If newItem is already in a list, it is removed from its previous list before it is inserted into this list.
260 removeFromOldOwnerListAndAdjustIndex(newItem, 0);
262 // Append the value and wrapper at the end of the list.
265 return newItem.release();
268 template<typename Derived, typename ItemProperty>
269 PassRefPtr<ItemProperty> NewSVGListPropertyHelper<Derived, ItemProperty>::replaceItem(PassRefPtr<ItemProperty> passNewItem, size_t index, ExceptionState& exceptionState)
271 if (!checkIndexBound(index, exceptionState))
274 RefPtr<ItemPropertyType> newItem = passNewItem;
276 // Spec: If newItem is already in a list, it is removed from its previous list before it is inserted into this list.
277 // 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.
278 if (!removeFromOldOwnerListAndAdjustIndex(newItem, &index)) {
279 // Replacing the item with itself is a no-op.
280 return newItem.release();
283 if (m_values.isEmpty()) {
284 // 'newItem' already lived in our list, we removed it, and now we're empty, which means there's nothing to replace.
285 exceptionState.throwDOMException(IndexSizeError, String::format("Failed to replace the provided item at index %zu.", index));
289 // Update the value at the desired position 'index'.
290 RefPtr<ItemPropertyType>& position = m_values[index];
291 ASSERT(position->ownerList() == this);
292 position->setOwnerList(0);
294 newItem->setOwnerList(this);
296 return newItem.release();
299 template<typename Derived, typename ItemProperty>
300 bool NewSVGListPropertyHelper<Derived, ItemProperty>::checkIndexBound(size_t index, ExceptionState& exceptionState)
302 if (index >= m_values.size()) {
303 exceptionState.throwDOMException(IndexSizeError, ExceptionMessages::indexExceedsMaximumBound("index", index, m_values.size()));
310 template<typename Derived, typename ItemProperty>
311 bool NewSVGListPropertyHelper<Derived, ItemProperty>::removeFromOldOwnerListAndAdjustIndex(PassRefPtr<ItemPropertyType> passItem, size_t* indexToModify)
313 RefPtr<ItemPropertyType> item = passItem;
315 RefPtr<Derived> ownerList = toDerived(item->ownerList());
319 // Spec: If newItem is already in a list, it is removed from its previous list before it is inserted into this list.
320 // 'newItem' is already living in another list. If it's not our list, synchronize the other lists wrappers after the removal.
321 bool livesInOtherList = ownerList.get() != this;
322 size_t indexToRemove = ownerList->findItem(item);
323 ASSERT(indexToRemove != WTF::kNotFound);
325 // Do not remove newItem if already in this list at the target index.
326 if (!livesInOtherList && indexToModify && indexToRemove == *indexToModify)
329 ownerList->removeItem(indexToRemove, ASSERT_NO_EXCEPTION);
334 // If the item lived in our list, adjust the insertion index.
335 if (!livesInOtherList) {
336 size_t& index = *indexToModify;
337 // 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.
338 if (static_cast<size_t>(indexToRemove) < index)
345 template<typename Derived, typename ItemProperty>
346 size_t NewSVGListPropertyHelper<Derived, ItemProperty>::findItem(PassRefPtr<ItemPropertyType> item)
348 return m_values.find(item);
351 template<typename Derived, typename ItemProperty>
352 void NewSVGListPropertyHelper<Derived, ItemProperty>::deepCopy(PassRefPtr<Derived> passFrom)
354 RefPtr<Derived> from = passFrom;
357 typename Vector<RefPtr<ItemPropertyType> >::const_iterator it = from->m_values.begin();
358 typename Vector<RefPtr<ItemPropertyType> >::const_iterator itEnd = from->m_values.end();
359 for (; it != itEnd; ++it) {
360 append((*it)->clone());
366 #endif // NewSVGListPropertyHelper_h