• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 SVGListPropertyTearOffHelper_h
32 #define SVGListPropertyTearOffHelper_h
33 
34 #include "bindings/v8/ExceptionState.h"
35 #include "core/svg/properties/SVGPropertyTearOff.h"
36 #include "wtf/HashMap.h"
37 #include "wtf/TypeTraits.h"
38 
39 namespace WebCore {
40 
41 template<typename ItemProperty>
42 class ListItemPropertyTraits {
43 public:
44     typedef ItemProperty ItemPropertyType;
45     typedef typename ItemPropertyType::TearOffType ItemTearOffType;
46 
getValueForInsertionFromTearOff(PassRefPtr<ItemTearOffType> passNewItem,SVGElement * contextElement,const QualifiedName & attributeName)47     static PassRefPtr<ItemPropertyType> getValueForInsertionFromTearOff(PassRefPtr<ItemTearOffType> passNewItem, SVGElement* contextElement, const QualifiedName& attributeName)
48     {
49         RefPtr<ItemTearOffType> newItem = passNewItem;
50 
51         // |newItem| is immutable, OR
52         // |newItem| belongs to a SVGElement, but it does not belong to an animated list
53         // (for example: "textElement.x.baseVal.appendItem(rectElement.width.baseVal)")
54         if (newItem->isImmutable()
55             || (newItem->contextElement() && !newItem->target()->ownerList())) {
56             // We have to copy the incoming |newItem|,
57             // Otherwise we'll end up having two tearoffs that operate on the same SVGProperty. Consider the example below:
58             // SVGRectElements SVGAnimatedLength 'width' property baseVal points to the same tear off object
59             // that's inserted into SVGTextElements SVGAnimatedLengthList 'x'. textElement.x.baseVal.getItem(0).value += 150 would
60             // mutate the rectElement width _and_ the textElement x list. That's obviously wrong, take care of that.
61             return newItem->target()->clone();
62         }
63 
64         newItem->attachToSVGElementAttribute(contextElement, attributeName);
65         return newItem->target();
66     }
67 
createTearOff(PassRefPtr<ItemPropertyType> value,SVGElement * contextElement,PropertyIsAnimValType propertyIsAnimVal,const QualifiedName & attributeName)68     static PassRefPtr<ItemTearOffType> createTearOff(PassRefPtr<ItemPropertyType> value, SVGElement* contextElement, PropertyIsAnimValType propertyIsAnimVal, const QualifiedName& attributeName)
69     {
70         return ItemTearOffType::create(value, contextElement, propertyIsAnimVal, attributeName);
71     }
72 };
73 
74 template<typename Derived, typename ListProperty>
75 class SVGListPropertyTearOffHelper : public SVGPropertyTearOff<ListProperty> {
76 public:
77     typedef ListProperty ListPropertyType;
78     typedef typename ListPropertyType::ItemPropertyType ItemPropertyType;
79     typedef typename ItemPropertyType::TearOffType ItemTearOffType;
80     typedef ListItemPropertyTraits<ItemPropertyType> ItemTraits;
81 
82     // SVG*List DOM interface:
83 
84     // WebIDL requires "unsigned long" type instead of size_t.
length()85     unsigned long length()
86     {
87         return toDerived()->target()->length();
88     }
89 
clear(ExceptionState & exceptionState)90     void clear(ExceptionState& exceptionState)
91     {
92         if (toDerived()->isImmutable()) {
93             exceptionState.throwDOMException(NoModificationAllowedError, "The object is read-only.");
94             return;
95         }
96 
97         toDerived()->target()->clear();
98     }
99 
initialize(PassRefPtr<ItemTearOffType> passItem,ExceptionState & exceptionState)100     PassRefPtr<ItemTearOffType> initialize(PassRefPtr<ItemTearOffType> passItem, ExceptionState& exceptionState)
101     {
102         RefPtr<ItemTearOffType> item = passItem;
103 
104         if (toDerived()->isImmutable()) {
105             exceptionState.throwDOMException(NoModificationAllowedError, "The object is read-only.");
106             return nullptr;
107         }
108 
109         if (!item) {
110             exceptionState.throwTypeError("Lists must be initialized with a valid item.");
111             return nullptr;
112         }
113 
114         RefPtr<ItemPropertyType> value = toDerived()->target()->initialize(getValueForInsertionFromTearOff(item));
115         toDerived()->commitChange();
116 
117         return createItemTearOff(value.release());
118     }
119 
getItem(unsigned long index,ExceptionState & exceptionState)120     PassRefPtr<ItemTearOffType> getItem(unsigned long index, ExceptionState& exceptionState)
121     {
122         RefPtr<ItemPropertyType> value = toDerived()->target()->getItem(index, exceptionState);
123         return createItemTearOff(value.release());
124     }
125 
insertItemBefore(PassRefPtr<ItemTearOffType> passItem,unsigned long index,ExceptionState & exceptionState)126     PassRefPtr<ItemTearOffType> insertItemBefore(PassRefPtr<ItemTearOffType> passItem, unsigned long index, ExceptionState& exceptionState)
127     {
128         RefPtr<ItemTearOffType> item = passItem;
129 
130         if (toDerived()->isImmutable()) {
131             exceptionState.throwDOMException(NoModificationAllowedError, "The object is read-only.");
132             return nullptr;
133         }
134 
135         if (!item) {
136             exceptionState.throwTypeError("An invalid item cannot be inserted to a list.");
137             return nullptr;
138         }
139 
140         RefPtr<ItemPropertyType> value = toDerived()->target()->insertItemBefore(getValueForInsertionFromTearOff(item), index);
141         toDerived()->commitChange();
142 
143         return createItemTearOff(value.release());
144     }
145 
replaceItem(PassRefPtr<ItemTearOffType> passItem,unsigned long index,ExceptionState & exceptionState)146     PassRefPtr<ItemTearOffType> replaceItem(PassRefPtr<ItemTearOffType> passItem, unsigned long index, ExceptionState& exceptionState)
147     {
148         RefPtr<ItemTearOffType> item = passItem;
149 
150         if (toDerived()->isImmutable()) {
151             exceptionState.throwDOMException(NoModificationAllowedError, "The object is read-only.");
152             return nullptr;
153         }
154 
155         if (!item) {
156             exceptionState.throwTypeError("An invalid item cannot be replaced with an existing list item.");
157             return nullptr;
158         }
159 
160         RefPtr<ItemPropertyType> value = toDerived()->target()->replaceItem(getValueForInsertionFromTearOff(item), index, exceptionState);
161         toDerived()->commitChange();
162 
163         return createItemTearOff(value.release());
164     }
165 
anonymousIndexedSetter(unsigned index,PassRefPtr<ItemTearOffType> passItem,ExceptionState & exceptionState)166     bool anonymousIndexedSetter(unsigned index, PassRefPtr<ItemTearOffType> passItem, ExceptionState& exceptionState)
167     {
168         replaceItem(passItem, index, exceptionState);
169         return true;
170     }
171 
removeItem(unsigned long index,ExceptionState & exceptionState)172     PassRefPtr<ItemTearOffType> removeItem(unsigned long index, ExceptionState& exceptionState)
173     {
174         RefPtr<ItemPropertyType> value = toDerived()->target()->removeItem(index, exceptionState);
175         toDerived()->commitChange();
176 
177         return createItemTearOff(value.release());
178     }
179 
appendItem(PassRefPtr<ItemTearOffType> passItem,ExceptionState & exceptionState)180     PassRefPtr<ItemTearOffType> appendItem(PassRefPtr<ItemTearOffType> passItem, ExceptionState& exceptionState)
181     {
182         RefPtr<ItemTearOffType> item = passItem;
183 
184         if (toDerived()->isImmutable()) {
185             exceptionState.throwDOMException(NoModificationAllowedError, "The object is read-only.");
186             return nullptr;
187         }
188 
189         if (!item) {
190             exceptionState.throwTypeError("An invalid item cannot be appended to a list.");
191             return nullptr;
192         }
193 
194         RefPtr<ItemPropertyType> value = toDerived()->target()->appendItem(getValueForInsertionFromTearOff(item));
195         toDerived()->commitChange();
196 
197         return createItemTearOff(value.release());
198     }
199 
200 protected:
201     SVGListPropertyTearOffHelper(PassRefPtr<ListPropertyType> target, SVGElement* contextElement, PropertyIsAnimValType propertyIsAnimVal, const QualifiedName& attributeName = QualifiedName::null())
202         : SVGPropertyTearOff<ListPropertyType>(target, contextElement, propertyIsAnimVal, attributeName)
203     {
204     }
205 
getValueForInsertionFromTearOff(PassRefPtr<ItemTearOffType> passNewItem)206     PassRefPtr<ItemPropertyType> getValueForInsertionFromTearOff(PassRefPtr<ItemTearOffType> passNewItem)
207     {
208         return ItemTraits::getValueForInsertionFromTearOff(passNewItem, toDerived()->contextElement(), toDerived()->attributeName());
209     }
210 
createItemTearOff(PassRefPtr<ItemPropertyType> value)211     PassRefPtr<ItemTearOffType> createItemTearOff(PassRefPtr<ItemPropertyType> value)
212     {
213         if (!value)
214             return nullptr;
215 
216         if (value->ownerList() == toDerived()->target())
217             return ItemTraits::createTearOff(value, toDerived()->contextElement(), toDerived()->propertyIsAnimVal(), toDerived()->attributeName());
218 
219         return ItemTraits::createTearOff(value, 0, PropertyIsNotAnimVal, QualifiedName::null());
220     }
221 
222 private:
toDerived()223     Derived* toDerived() { return static_cast<Derived*>(this); }
224 };
225 
226 }
227 
228 #endif // SVGListPropertyTearOffHelper_h
229