Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / svg / properties / SVGListPropertyTearOffHelper.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 SVGListPropertyTearOffHelper_h
32 #define SVGListPropertyTearOffHelper_h
33
34 #include "bindings/core/v8/ExceptionState.h"
35 #include "core/svg/properties/SVGPropertyTearOff.h"
36 #include "wtf/HashMap.h"
37 #include "wtf/TypeTraits.h"
38
39 namespace blink {
40
41 template<typename ItemProperty>
42 class ListItemPropertyTraits {
43 public:
44     typedef ItemProperty ItemPropertyType;
45     typedef typename ItemPropertyType::TearOffType ItemTearOffType;
46
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
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.
85     unsigned long length()
86     {
87         return toDerived()->target()->length();
88     }
89
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
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
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
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
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
166     bool anonymousIndexedSetter(unsigned index, PassRefPtr<ItemTearOffType> passItem, ExceptionState& exceptionState)
167     {
168         replaceItem(passItem, index, exceptionState);
169         return true;
170     }
171
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
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
206     PassRefPtr<ItemPropertyType> getValueForInsertionFromTearOff(PassRefPtr<ItemTearOffType> passNewItem)
207     {
208         return ItemTraits::getValueForInsertionFromTearOff(passNewItem, toDerived()->contextElement(), toDerived()->attributeName());
209     }
210
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:
223     Derived* toDerived() { return static_cast<Derived*>(this); }
224 };
225
226 }
227
228 #endif // SVGListPropertyTearOffHelper_h