Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / svg / properties / NewSVGListPropertyHelper.h
1 /*
2  * Copyright (C) 2013 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
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
13  * distribution.
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.
17  *
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.
29  */
30
31 #ifndef NewSVGListPropertyHelper_h
32 #define NewSVGListPropertyHelper_h
33
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"
40
41 namespace WebCore {
42
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 {
47 public:
48     typedef ItemProperty ItemPropertyType;
49
50     NewSVGListPropertyHelper()
51         : NewSVGPropertyBase(Derived::classType())
52     {
53     }
54
55     ~NewSVGListPropertyHelper()
56     {
57         clear();
58     }
59
60     // used from Blink C++ code:
61
62     ItemPropertyType* at(size_t index)
63     {
64         ASSERT(index < m_values.size());
65         ASSERT(m_values.at(index)->ownerList() == this);
66         return m_values.at(index).get();
67     }
68
69     const ItemPropertyType* at(size_t index) const
70     {
71         return const_cast<NewSVGListPropertyHelper<Derived, ItemProperty>*>(this)->at(index);
72     }
73
74     class ConstIterator {
75     private:
76         typedef typename Vector<RefPtr<ItemPropertyType> >::const_iterator WrappedType;
77
78     public:
79         ConstIterator(WrappedType it)
80             : m_it(it)
81         {
82         }
83
84         ConstIterator& operator++() { ++m_it; return *this; }
85
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; }
88
89         PassRefPtr<ItemPropertyType> operator*() { return *m_it; }
90         PassRefPtr<ItemPropertyType> operator->() { return *m_it; }
91
92     private:
93         WrappedType m_it;
94     };
95
96     ConstIterator begin() const
97     {
98         return ConstIterator(m_values.begin());
99     }
100
101     ConstIterator end() const
102     {
103         return ConstIterator(m_values.end());
104     }
105
106     void append(PassRefPtr<ItemPropertyType> passNewItem)
107     {
108         RefPtr<ItemPropertyType> newItem = passNewItem;
109
110         ASSERT(newItem);
111         m_values.append(newItem);
112         newItem->setOwnerList(this);
113     }
114
115     bool operator==(const Derived&) const;
116     bool operator!=(const Derived& other) const
117     {
118         return !(*this == other);
119     }
120
121     bool isEmpty() const
122     {
123         return !numberOfItems();
124     }
125
126     // SVGList*Property DOM spec:
127
128     size_t numberOfItems() const
129     {
130         return m_values.size();
131     }
132
133     void clear();
134
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&);
141
142 protected:
143     void deepCopy(PassRefPtr<Derived>);
144
145 private:
146     inline bool checkIndexBound(size_t, ExceptionState&);
147     bool removeFromOldOwnerListAndAdjustIndex(PassRefPtr<ItemPropertyType>, size_t* indexToModify);
148     size_t findItem(PassRefPtr<ItemPropertyType>);
149
150     Vector<RefPtr<ItemPropertyType> > m_values;
151
152     static PassRefPtr<Derived> toDerived(PassRefPtr<NewSVGPropertyBase> passBase)
153     {
154         if (!passBase)
155             return 0;
156
157         RefPtr<NewSVGPropertyBase> base = passBase;
158         ASSERT(base->type() == Derived::classType());
159         return static_pointer_cast<Derived>(base.release());
160     }
161 };
162
163 template<typename Derived, typename ItemProperty>
164 bool NewSVGListPropertyHelper<Derived, ItemProperty>::operator==(const Derived& other) const
165 {
166     if (numberOfItems() != other.numberOfItems())
167         return false;
168
169     size_t length = numberOfItems();
170     for (size_t i = 0; i < length; ++i) {
171         if (*at(i) != *other.at(i))
172             return false;
173     }
174
175     return true;
176 }
177
178 template<typename Derived, typename ItemProperty>
179 void NewSVGListPropertyHelper<Derived, ItemProperty>::clear()
180 {
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);
187     }
188
189     m_values.clear();
190 }
191
192 template<typename Derived, typename ItemProperty>
193 PassRefPtr<ItemProperty> NewSVGListPropertyHelper<Derived, ItemProperty>::initialize(PassRefPtr<ItemProperty> passNewItem)
194 {
195     RefPtr<ItemPropertyType> newItem = passNewItem;
196
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);
199
200     // Spec: Clears all existing current items from the list and re-initializes the list to hold the single item specified by the parameter.
201     clear();
202     append(newItem);
203     return newItem.release();
204 }
205
206 template<typename Derived, typename ItemProperty>
207 PassRefPtr<ItemProperty> NewSVGListPropertyHelper<Derived, ItemProperty>::getItem(size_t index, ExceptionState& exceptionState)
208 {
209     if (!checkIndexBound(index, exceptionState))
210         return 0;
211
212     ASSERT(index < m_values.size());
213     ASSERT(m_values.at(index)->ownerList() == this);
214     return m_values.at(index);
215 }
216
217 template<typename Derived, typename ItemProperty>
218 PassRefPtr<ItemProperty> NewSVGListPropertyHelper<Derived, ItemProperty>::insertItemBefore(PassRefPtr<ItemProperty> passNewItem, size_t index)
219 {
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();
223
224     RefPtr<ItemPropertyType> newItem = passNewItem;
225
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();
230     }
231
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);
236
237     return newItem.release();
238 }
239
240 template<typename Derived, typename ItemProperty>
241 PassRefPtr<ItemProperty> NewSVGListPropertyHelper<Derived, ItemProperty>::removeItem(size_t index, ExceptionState& exceptionState)
242 {
243     if (index >= m_values.size()) {
244         exceptionState.throwDOMException(IndexSizeError, ExceptionMessages::indexExceedsMaximumBound("index", index, m_values.size()));
245         return 0;
246     }
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();
252 }
253
254 template<typename Derived, typename ItemProperty>
255 PassRefPtr<ItemProperty> NewSVGListPropertyHelper<Derived, ItemProperty>::appendItem(PassRefPtr<ItemProperty> passNewItem)
256 {
257     RefPtr<ItemPropertyType> newItem = passNewItem;
258
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);
261
262     // Append the value and wrapper at the end of the list.
263     append(newItem);
264
265     return newItem.release();
266 }
267
268 template<typename Derived, typename ItemProperty>
269 PassRefPtr<ItemProperty> NewSVGListPropertyHelper<Derived, ItemProperty>::replaceItem(PassRefPtr<ItemProperty> passNewItem, size_t index, ExceptionState& exceptionState)
270 {
271     if (!checkIndexBound(index, exceptionState))
272         return 0;
273
274     RefPtr<ItemPropertyType> newItem = passNewItem;
275
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();
281     }
282
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));
286         return 0;
287     }
288
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);
293     position = newItem;
294     newItem->setOwnerList(this);
295
296     return newItem.release();
297 }
298
299 template<typename Derived, typename ItemProperty>
300 bool NewSVGListPropertyHelper<Derived, ItemProperty>::checkIndexBound(size_t index, ExceptionState& exceptionState)
301 {
302     if (index >= m_values.size()) {
303         exceptionState.throwDOMException(IndexSizeError, ExceptionMessages::indexExceedsMaximumBound("index", index, m_values.size()));
304         return false;
305     }
306
307     return true;
308 }
309
310 template<typename Derived, typename ItemProperty>
311 bool NewSVGListPropertyHelper<Derived, ItemProperty>::removeFromOldOwnerListAndAdjustIndex(PassRefPtr<ItemPropertyType> passItem, size_t* indexToModify)
312 {
313     RefPtr<ItemPropertyType> item = passItem;
314     ASSERT(item);
315     RefPtr<Derived> ownerList = toDerived(item->ownerList());
316     if (!ownerList)
317         return true;
318
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);
324
325     // Do not remove newItem if already in this list at the target index.
326     if (!livesInOtherList && indexToModify && indexToRemove == *indexToModify)
327         return false;
328
329     ownerList->removeItem(indexToRemove, ASSERT_NO_EXCEPTION);
330
331     if (!indexToModify)
332         return true;
333
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)
339             --index;
340     }
341
342     return true;
343 }
344
345 template<typename Derived, typename ItemProperty>
346 size_t NewSVGListPropertyHelper<Derived, ItemProperty>::findItem(PassRefPtr<ItemPropertyType> item)
347 {
348     return m_values.find(item);
349 }
350
351 template<typename Derived, typename ItemProperty>
352 void NewSVGListPropertyHelper<Derived, ItemProperty>::deepCopy(PassRefPtr<Derived> passFrom)
353 {
354     RefPtr<Derived> from = passFrom;
355
356     clear();
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());
361     }
362 }
363
364 }
365
366 #endif // NewSVGListPropertyHelper_h