| 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 |