OLD | NEW |
| (Empty) |
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 Wrapp
edType; | |
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 lastAppended() const | |
102 { | |
103 return ConstIterator(m_values.begin() + m_values.size() - 1); | |
104 } | |
105 | |
106 ConstIterator end() const | |
107 { | |
108 return ConstIterator(m_values.end()); | |
109 } | |
110 | |
111 void append(PassRefPtr<ItemPropertyType> passNewItem) | |
112 { | |
113 RefPtr<ItemPropertyType> newItem = passNewItem; | |
114 | |
115 ASSERT(newItem); | |
116 m_values.append(newItem); | |
117 newItem->setOwnerList(this); | |
118 } | |
119 | |
120 bool operator==(const Derived&) const; | |
121 bool operator!=(const Derived& other) const | |
122 { | |
123 return !(*this == other); | |
124 } | |
125 | |
126 bool isEmpty() const | |
127 { | |
128 return !length(); | |
129 } | |
130 | |
131 // SVGList*Property DOM spec: | |
132 | |
133 size_t length() const | |
134 { | |
135 return m_values.size(); | |
136 } | |
137 | |
138 void clear(); | |
139 | |
140 PassRefPtr<ItemPropertyType> initialize(PassRefPtr<ItemPropertyType>); | |
141 PassRefPtr<ItemPropertyType> getItem(size_t, ExceptionState&); | |
142 PassRefPtr<ItemPropertyType> insertItemBefore(PassRefPtr<ItemPropertyType>,
size_t); | |
143 PassRefPtr<ItemPropertyType> removeItem(size_t, ExceptionState&); | |
144 PassRefPtr<ItemPropertyType> appendItem(PassRefPtr<ItemPropertyType>); | |
145 PassRefPtr<ItemPropertyType> replaceItem(PassRefPtr<ItemPropertyType>, size_
t, ExceptionState&); | |
146 | |
147 protected: | |
148 void deepCopy(PassRefPtr<Derived>); | |
149 | |
150 private: | |
151 inline bool checkIndexBound(size_t, ExceptionState&); | |
152 bool removeFromOldOwnerListAndAdjustIndex(PassRefPtr<ItemPropertyType>, size
_t* indexToModify); | |
153 size_t findItem(PassRefPtr<ItemPropertyType>); | |
154 | |
155 Vector<RefPtr<ItemPropertyType> > m_values; | |
156 | |
157 static PassRefPtr<Derived> toDerived(PassRefPtr<NewSVGPropertyBase> passBase
) | |
158 { | |
159 if (!passBase) | |
160 return nullptr; | |
161 | |
162 RefPtr<NewSVGPropertyBase> base = passBase; | |
163 ASSERT(base->type() == Derived::classType()); | |
164 return static_pointer_cast<Derived>(base); | |
165 } | |
166 }; | |
167 | |
168 template<typename Derived, typename ItemProperty> | |
169 bool NewSVGListPropertyHelper<Derived, ItemProperty>::operator==(const Derived&
other) const | |
170 { | |
171 if (length() != other.length()) | |
172 return false; | |
173 | |
174 size_t size = length(); | |
175 for (size_t i = 0; i < size; ++i) { | |
176 if (*at(i) != *other.at(i)) | |
177 return false; | |
178 } | |
179 | |
180 return true; | |
181 } | |
182 | |
183 template<typename Derived, typename ItemProperty> | |
184 void NewSVGListPropertyHelper<Derived, ItemProperty>::clear() | |
185 { | |
186 // detach all list items as they are no longer part of this list | |
187 typename Vector<RefPtr<ItemPropertyType> >::const_iterator it = m_values.beg
in(); | |
188 typename Vector<RefPtr<ItemPropertyType> >::const_iterator itEnd = m_values.
end(); | |
189 for (; it != itEnd; ++it) { | |
190 ASSERT((*it)->ownerList() == this); | |
191 (*it)->setOwnerList(0); | |
192 } | |
193 | |
194 m_values.clear(); | |
195 } | |
196 | |
197 template<typename Derived, typename ItemProperty> | |
198 PassRefPtr<ItemProperty> NewSVGListPropertyHelper<Derived, ItemProperty>::initia
lize(PassRefPtr<ItemProperty> passNewItem) | |
199 { | |
200 RefPtr<ItemPropertyType> newItem = passNewItem; | |
201 | |
202 // Spec: If the inserted item is already in a list, it is removed from its p
revious list before it is inserted into this list. | |
203 removeFromOldOwnerListAndAdjustIndex(newItem, 0); | |
204 | |
205 // Spec: Clears all existing current items from the list and re-initializes
the list to hold the single item specified by the parameter. | |
206 clear(); | |
207 append(newItem); | |
208 return newItem.release(); | |
209 } | |
210 | |
211 template<typename Derived, typename ItemProperty> | |
212 PassRefPtr<ItemProperty> NewSVGListPropertyHelper<Derived, ItemProperty>::getIte
m(size_t index, ExceptionState& exceptionState) | |
213 { | |
214 if (!checkIndexBound(index, exceptionState)) | |
215 return nullptr; | |
216 | |
217 ASSERT(index < m_values.size()); | |
218 ASSERT(m_values.at(index)->ownerList() == this); | |
219 return m_values.at(index); | |
220 } | |
221 | |
222 template<typename Derived, typename ItemProperty> | |
223 PassRefPtr<ItemProperty> NewSVGListPropertyHelper<Derived, ItemProperty>::insert
ItemBefore(PassRefPtr<ItemProperty> passNewItem, size_t index) | |
224 { | |
225 // Spec: If the index is greater than or equal to length, then the new item
is appended to the end of the list. | |
226 if (index > m_values.size()) | |
227 index = m_values.size(); | |
228 | |
229 RefPtr<ItemPropertyType> newItem = passNewItem; | |
230 | |
231 // Spec: If newItem is already in a list, it is removed from its previous li
st before it is inserted into this list. | |
232 if (!removeFromOldOwnerListAndAdjustIndex(newItem, &index)) { | |
233 // Inserting the item before itself is a no-op. | |
234 return newItem.release(); | |
235 } | |
236 | |
237 // Spec: Inserts a new item into the list at the specified position. The ind
ex of the item before which the new item is to be | |
238 // inserted. The first item is number 0. If the index is equal to 0, then th
e new item is inserted at the front of the list. | |
239 m_values.insert(index, newItem); | |
240 newItem->setOwnerList(this); | |
241 | |
242 return newItem.release(); | |
243 } | |
244 | |
245 template<typename Derived, typename ItemProperty> | |
246 PassRefPtr<ItemProperty> NewSVGListPropertyHelper<Derived, ItemProperty>::remove
Item(size_t index, ExceptionState& exceptionState) | |
247 { | |
248 if (index >= m_values.size()) { | |
249 exceptionState.throwDOMException(IndexSizeError, ExceptionMessages::inde
xExceedsMaximumBound("index", index, m_values.size())); | |
250 return nullptr; | |
251 } | |
252 ASSERT(m_values.at(index)->ownerList() == this); | |
253 RefPtr<ItemPropertyType> oldItem = m_values.at(index); | |
254 m_values.remove(index); | |
255 oldItem->setOwnerList(0); | |
256 return oldItem.release(); | |
257 } | |
258 | |
259 template<typename Derived, typename ItemProperty> | |
260 PassRefPtr<ItemProperty> NewSVGListPropertyHelper<Derived, ItemProperty>::append
Item(PassRefPtr<ItemProperty> passNewItem) | |
261 { | |
262 RefPtr<ItemPropertyType> newItem = passNewItem; | |
263 | |
264 // Spec: If newItem is already in a list, it is removed from its previous li
st before it is inserted into this list. | |
265 removeFromOldOwnerListAndAdjustIndex(newItem, 0); | |
266 | |
267 // Append the value and wrapper at the end of the list. | |
268 append(newItem); | |
269 | |
270 return newItem.release(); | |
271 } | |
272 | |
273 template<typename Derived, typename ItemProperty> | |
274 PassRefPtr<ItemProperty> NewSVGListPropertyHelper<Derived, ItemProperty>::replac
eItem(PassRefPtr<ItemProperty> passNewItem, size_t index, ExceptionState& except
ionState) | |
275 { | |
276 if (!checkIndexBound(index, exceptionState)) | |
277 return nullptr; | |
278 | |
279 RefPtr<ItemPropertyType> newItem = passNewItem; | |
280 | |
281 // Spec: If newItem is already in a list, it is removed from its previous li
st before it is inserted into this list. | |
282 // Spec: If the item is already in this list, note that the index of the ite
m to replace is before the removal of the item. | |
283 if (!removeFromOldOwnerListAndAdjustIndex(newItem, &index)) { | |
284 // Replacing the item with itself is a no-op. | |
285 return newItem.release(); | |
286 } | |
287 | |
288 if (m_values.isEmpty()) { | |
289 // 'newItem' already lived in our list, we removed it, and now we're emp
ty, which means there's nothing to replace. | |
290 exceptionState.throwDOMException(IndexSizeError, String::format("Failed
to replace the provided item at index %zu.", index)); | |
291 return nullptr; | |
292 } | |
293 | |
294 // Update the value at the desired position 'index'. | |
295 RefPtr<ItemPropertyType>& position = m_values[index]; | |
296 ASSERT(position->ownerList() == this); | |
297 position->setOwnerList(0); | |
298 position = newItem; | |
299 newItem->setOwnerList(this); | |
300 | |
301 return newItem.release(); | |
302 } | |
303 | |
304 template<typename Derived, typename ItemProperty> | |
305 bool NewSVGListPropertyHelper<Derived, ItemProperty>::checkIndexBound(size_t ind
ex, ExceptionState& exceptionState) | |
306 { | |
307 if (index >= m_values.size()) { | |
308 exceptionState.throwDOMException(IndexSizeError, ExceptionMessages::inde
xExceedsMaximumBound("index", index, m_values.size())); | |
309 return false; | |
310 } | |
311 | |
312 return true; | |
313 } | |
314 | |
315 template<typename Derived, typename ItemProperty> | |
316 bool NewSVGListPropertyHelper<Derived, ItemProperty>::removeFromOldOwnerListAndA
djustIndex(PassRefPtr<ItemPropertyType> passItem, size_t* indexToModify) | |
317 { | |
318 RefPtr<ItemPropertyType> item = passItem; | |
319 ASSERT(item); | |
320 RefPtr<Derived> ownerList = toDerived(item->ownerList()); | |
321 if (!ownerList) | |
322 return true; | |
323 | |
324 // Spec: If newItem is already in a list, it is removed from its previous li
st before it is inserted into this list. | |
325 // 'newItem' is already living in another list. If it's not our list, synchr
onize the other lists wrappers after the removal. | |
326 bool livesInOtherList = ownerList.get() != this; | |
327 size_t indexToRemove = ownerList->findItem(item); | |
328 ASSERT(indexToRemove != WTF::kNotFound); | |
329 | |
330 // Do not remove newItem if already in this list at the target index. | |
331 if (!livesInOtherList && indexToModify && indexToRemove == *indexToModify) | |
332 return false; | |
333 | |
334 ownerList->removeItem(indexToRemove, ASSERT_NO_EXCEPTION); | |
335 | |
336 if (!indexToModify) | |
337 return true; | |
338 | |
339 // If the item lived in our list, adjust the insertion index. | |
340 if (!livesInOtherList) { | |
341 size_t& index = *indexToModify; | |
342 // 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. | |
343 if (static_cast<size_t>(indexToRemove) < index) | |
344 --index; | |
345 } | |
346 | |
347 return true; | |
348 } | |
349 | |
350 template<typename Derived, typename ItemProperty> | |
351 size_t NewSVGListPropertyHelper<Derived, ItemProperty>::findItem(PassRefPtr<Item
PropertyType> item) | |
352 { | |
353 return m_values.find(item); | |
354 } | |
355 | |
356 template<typename Derived, typename ItemProperty> | |
357 void NewSVGListPropertyHelper<Derived, ItemProperty>::deepCopy(PassRefPtr<Derive
d> passFrom) | |
358 { | |
359 RefPtr<Derived> from = passFrom; | |
360 | |
361 clear(); | |
362 typename Vector<RefPtr<ItemPropertyType> >::const_iterator it = from->m_valu
es.begin(); | |
363 typename Vector<RefPtr<ItemPropertyType> >::const_iterator itEnd = from->m_v
alues.end(); | |
364 for (; it != itEnd; ++it) { | |
365 append((*it)->clone()); | |
366 } | |
367 } | |
368 | |
369 } | |
370 | |
371 #endif // NewSVGListPropertyHelper_h | |
OLD | NEW |