1/*
2 * Copyright (C) 2018-2019 Apple 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
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include "SVGAnimatedPropertyAccessorImpl.h"
29#include "SVGAnimatedPropertyPairAccessorImpl.h"
30#include "SVGPropertyAccessorImpl.h"
31#include "SVGPropertyRegistry.h"
32#include <wtf/HashMap.h>
33
34namespace WebCore {
35
36class SVGAttributeAnimator;
37
38template<typename OwnerType, typename... BaseTypes>
39class SVGPropertyOwnerRegistry : public SVGPropertyRegistry {
40public:
41 SVGPropertyOwnerRegistry(OwnerType& owner)
42 : m_owner(owner)
43 {
44 }
45
46 template<const LazyNeverDestroyed<const QualifiedName>& attributeName, Ref<SVGStringList> OwnerType::*property>
47 static void registerProperty()
48 {
49 registerProperty(attributeName, SVGStringListAccessor<OwnerType>::template singleton<property>());
50 }
51
52 template<const LazyNeverDestroyed<const QualifiedName>& attributeName, Ref<SVGTransformList> OwnerType::*property>
53 static void registerProperty()
54 {
55 registerProperty(attributeName, SVGTransformListAccessor<OwnerType>::template singleton<property>());
56 }
57
58 template<const LazyNeverDestroyed<const QualifiedName>& attributeName, Ref<SVGAnimatedBoolean> OwnerType::*property>
59 static void registerProperty()
60 {
61 registerProperty(attributeName, SVGAnimatedBooleanAccessor<OwnerType>::template singleton<property>());
62 }
63
64 template<const LazyNeverDestroyed<const QualifiedName>& attributeName, typename EnumType, Ref<SVGAnimatedEnumeration> OwnerType::*property>
65 static void registerProperty()
66 {
67 registerProperty(attributeName, SVGAnimatedEnumerationAccessor<OwnerType, EnumType>::template singleton<property>());
68 }
69
70 template<const LazyNeverDestroyed<const QualifiedName>& attributeName, Ref<SVGAnimatedInteger> OwnerType::*property>
71 static void registerProperty()
72 {
73 registerProperty(attributeName, SVGAnimatedIntegerAccessor<OwnerType>::template singleton<property>());
74 }
75
76 template<const LazyNeverDestroyed<const QualifiedName>& attributeName, Ref<SVGAnimatedLength> OwnerType::*property>
77 static void registerProperty()
78 {
79 registerProperty(attributeName, SVGAnimatedLengthAccessor<OwnerType>::template singleton<property>());
80 }
81
82 template<const LazyNeverDestroyed<const QualifiedName>& attributeName, Ref<SVGAnimatedLengthList> OwnerType::*property>
83 static void registerProperty()
84 {
85 registerProperty(attributeName, SVGAnimatedLengthListAccessor<OwnerType>::template singleton<property>());
86 }
87
88 template<const LazyNeverDestroyed<const QualifiedName>& attributeName, Ref<SVGAnimatedNumber> OwnerType::*property>
89 static void registerProperty()
90 {
91 registerProperty(attributeName, SVGAnimatedNumberAccessor<OwnerType>::template singleton<property>());
92 }
93
94 template<const LazyNeverDestroyed<const QualifiedName>& attributeName, Ref<SVGAnimatedNumberList> OwnerType::*property>
95 static void registerProperty()
96 {
97 registerProperty(attributeName, SVGAnimatedNumberListAccessor<OwnerType>::template singleton<property>());
98 }
99
100 template<const LazyNeverDestroyed<const QualifiedName>& attributeName, Ref<SVGAnimatedAngle> OwnerType::*property1, Ref<SVGAnimatedOrientType> OwnerType::*property2>
101 static void registerProperty()
102 {
103 registerProperty(attributeName, SVGAnimatedAngleOrientAccessor<OwnerType>::template singleton<property1, property2>());
104 }
105
106 template<const LazyNeverDestroyed<const QualifiedName>& attributeName, Ref<SVGAnimatedPathSegList> OwnerType::*property>
107 static void registerProperty()
108 {
109 registerProperty(attributeName, SVGAnimatedPathSegListAccessor<OwnerType>::template singleton<property>());
110 }
111
112 template<const LazyNeverDestroyed<const QualifiedName>& attributeName, Ref<SVGAnimatedPointList> OwnerType::*property>
113 static void registerProperty()
114 {
115 registerProperty(attributeName, SVGAnimatedPointListAccessor<OwnerType>::template singleton<property>());
116 }
117
118 template<const LazyNeverDestroyed<const QualifiedName>& attributeName, Ref<SVGAnimatedPreserveAspectRatio> OwnerType::*property>
119 static void registerProperty()
120 {
121 registerProperty(attributeName, SVGAnimatedPreserveAspectRatioAccessor<OwnerType>::template singleton<property>());
122 }
123
124 template<const LazyNeverDestroyed<const QualifiedName>& attributeName, Ref<SVGAnimatedRect> OwnerType::*property>
125 static void registerProperty()
126 {
127 registerProperty(attributeName, SVGAnimatedRectAccessor<OwnerType>::template singleton<property>());
128 }
129
130 template<const LazyNeverDestroyed<const QualifiedName>& attributeName, Ref<SVGAnimatedString> OwnerType::*property>
131 static void registerProperty()
132 {
133 registerProperty(attributeName, SVGAnimatedStringAccessor<OwnerType>::template singleton<property>());
134 }
135
136 template<const LazyNeverDestroyed<const QualifiedName>& attributeName, Ref<SVGAnimatedTransformList> OwnerType::*property>
137 static void registerProperty()
138 {
139 registerProperty(attributeName, SVGAnimatedTransformListAccessor<OwnerType>::template singleton<property>());
140 }
141
142 template<const LazyNeverDestroyed<const QualifiedName>& attributeName, Ref<SVGAnimatedInteger> OwnerType::*property1, Ref<SVGAnimatedInteger> OwnerType::*property2>
143 static void registerProperty()
144 {
145 registerProperty(attributeName, SVGAnimatedIntegerPairAccessor<OwnerType>::template singleton<property1, property2>());
146 }
147
148 template<const LazyNeverDestroyed<const QualifiedName>& attributeName, Ref<SVGAnimatedNumber> OwnerType::*property1, Ref<SVGAnimatedNumber> OwnerType::*property2>
149 static void registerProperty()
150 {
151 registerProperty(attributeName, SVGAnimatedNumberPairAccessor<OwnerType>::template singleton<property1, property2>());
152 }
153
154 // Enumerate all the SVGMemberAccessors recursively. The functor will be called and will
155 // be given the pair<QualifiedName, SVGMemberAccessor> till the functor returns false.
156 template<typename Functor>
157 static bool enumerateRecursively(const Functor& functor)
158 {
159 for (const auto& entry : attributeNameToAccessorMap()) {
160 if (!functor(entry))
161 return false;
162 }
163 return enumerateRecursivelyBaseTypes(functor);
164 }
165
166 // Returns true if OwnerType owns a property whose name is attributeName.
167 static bool isKnownAttribute(const QualifiedName& attributeName)
168 {
169 return findAccessor(attributeName);
170 }
171
172 // Returns true if OwnerType owns a property whose name is attributeName
173 // and its type is SVGAnimatedLength.
174 static bool isAnimatedLengthAttribute(const QualifiedName& attributeName)
175 {
176 if (const auto* accessor = findAccessor(attributeName))
177 return accessor->isAnimatedLength();
178 return false;
179 }
180
181 QualifiedName propertyAttributeName(const SVGProperty& property) const override
182 {
183 QualifiedName attributeName = nullQName();
184 enumerateRecursively([&](const auto& entry) -> bool {
185 if (!entry.value->matches(m_owner, property))
186 return true;
187 attributeName = entry.key;
188 return false;
189 });
190 return attributeName;
191 }
192
193 QualifiedName animatedPropertyAttributeName(const SVGAnimatedProperty& animatedProperty) const override
194 {
195 QualifiedName attributeName = nullQName();
196 enumerateRecursively([&](const auto& entry) -> bool {
197 if (!entry.value->matches(m_owner, animatedProperty))
198 return true;
199 attributeName = entry.key;
200 return false;
201 });
202 return attributeName;
203 }
204
205 // Detach all the properties recursively from their OwnerTypes.
206 void detachAllProperties() const override
207 {
208 enumerateRecursively([&](const auto& entry) -> bool {
209 entry.value->detach(m_owner);
210 return true;
211 });
212 }
213
214 // Finds the property whose name is attributeName and returns the synchronize
215 // string through the associated SVGMemberAccessor.
216 Optional<String> synchronize(const QualifiedName& attributeName) const override
217 {
218 Optional<String> value;
219 enumerateRecursively([&](const auto& entry) -> bool {
220 if (!entry.key.matches(attributeName))
221 return true;
222 value = entry.value->synchronize(m_owner);
223 return false;
224 });
225 return value;
226 }
227
228 // Enumerate recursively the SVGMemberAccessors of the OwnerType and all its BaseTypes.
229 // Collect all the pairs <AttributeName, String> only for the dirty properties.
230 HashMap<QualifiedName, String> synchronizeAllAttributes() const override
231 {
232 HashMap<QualifiedName, String> map;
233 enumerateRecursively([&](const auto& entry) -> bool {
234 if (auto string = entry.value->synchronize(m_owner))
235 map.add(entry.key, *string);
236 return true;
237 });
238 return map;
239 }
240
241 bool isAnimatedPropertyAttribute(const QualifiedName& attributeName) const override
242 {
243 bool isAnimatedPropertyAttribute = false;
244 enumerateRecursively([&attributeName, &isAnimatedPropertyAttribute](const auto& entry) -> bool {
245 if (!entry.key.matches(attributeName))
246 return true;
247 isAnimatedPropertyAttribute = entry.value->isAnimatedProperty();
248 return false;
249 });
250 return isAnimatedPropertyAttribute;
251 }
252
253 bool isAnimatedStylePropertyAttribute(const QualifiedName& attributeName) const override
254 {
255 static NeverDestroyed<HashSet<QualifiedName::QualifiedNameImpl*>> animatedStyleAttributes = std::initializer_list<QualifiedName::QualifiedNameImpl*> {
256 SVGNames::cxAttr->impl(),
257 SVGNames::cyAttr->impl(),
258 SVGNames::rAttr->impl(),
259 SVGNames::rxAttr->impl(),
260 SVGNames::ryAttr->impl(),
261 SVGNames::heightAttr->impl(),
262 SVGNames::widthAttr->impl(),
263 SVGNames::xAttr->impl(),
264 SVGNames::yAttr->impl()
265 };
266 return isAnimatedLengthAttribute(attributeName) && animatedStyleAttributes.get().contains(attributeName.impl());
267 }
268
269 std::unique_ptr<SVGAttributeAnimator> createAnimator(const QualifiedName& attributeName, AnimationMode animationMode, CalcMode calcMode, bool isAccumulated, bool isAdditive) const override
270 {
271 std::unique_ptr<SVGAttributeAnimator> animator;
272 enumerateRecursively([&](const auto& entry) -> bool {
273 if (!entry.key.matches(attributeName))
274 return true;
275 animator = entry.value->createAnimator(m_owner, attributeName, animationMode, calcMode, isAccumulated, isAdditive);
276 return false;
277 });
278 return animator;
279 }
280
281 void appendAnimatedInstance(const QualifiedName& attributeName, SVGAttributeAnimator& animator) const override
282 {
283 enumerateRecursively([&](const auto& entry) -> bool {
284 if (!entry.key.matches(attributeName))
285 return true;
286 entry.value->appendAnimatedInstance(m_owner, animator);
287 return false;
288 });
289 }
290
291private:
292 // Singleton map for every OwnerType.
293 static HashMap<QualifiedName, const SVGMemberAccessor<OwnerType>*>& attributeNameToAccessorMap()
294 {
295 static NeverDestroyed<HashMap<QualifiedName, const SVGMemberAccessor<OwnerType>*>> attributeNameToAccessorMap;
296 return attributeNameToAccessorMap;
297 }
298
299 static void registerProperty(const QualifiedName& attributeName, const SVGMemberAccessor<OwnerType>& propertyAccessor)
300 {
301 attributeNameToAccessorMap().add(attributeName, &propertyAccessor);
302 }
303
304 // This is a template function with parameter 'I' whose default value = 0. So you can call it without any parameter
305 // from enumerateRecursively(). It returns true and is enable_if<I == sizeof...(BaseTypes)>. So it is mainly for
306 // breaking the recursion.
307 template<typename Functor, size_t I = 0>
308 static typename std::enable_if<I == sizeof...(BaseTypes), bool>::type enumerateRecursivelyBaseTypes(const Functor&) { return true; }
309
310 // This version of animatedTypesBaseTypes() is enable_if<I < sizeof...(BaseTypes)>.
311 template<typename Functor, size_t I = 0>
312 static typename std::enable_if<I < sizeof...(BaseTypes), bool>::type enumerateRecursivelyBaseTypes(const Functor& functor)
313 {
314 // Get the base type at index 'I' using std::tuple and std::tuple_element.
315 using BaseType = typename std::tuple_element<I, typename std::tuple<BaseTypes...>>::type;
316 if (!BaseType::PropertyRegistry::enumerateRecursively(functor))
317 return false;
318 // BaseType does not want to break the recursion. So recurse to the next BaseType.
319 return enumerateRecursivelyBaseTypes<Functor, I + 1>(functor);
320 }
321
322 static const SVGMemberAccessor<OwnerType>* findAccessor(const QualifiedName& attributeName)
323 {
324 // Here we need to loop through the entries in the map and use matches() to compare them with attributeName.
325 // m_map.contains() uses QualifiedName::operator==() which compares the impl pointers only while matches()
326 // compares the contents if the impl pointers differ.
327 auto it = std::find_if(attributeNameToAccessorMap().begin(), attributeNameToAccessorMap().end(), [&attributeName](const auto& entry) -> bool {
328 return entry.key.matches(attributeName);
329 });
330 return it != attributeNameToAccessorMap().end() ? it->value : nullptr;
331 }
332
333 OwnerType& m_owner;
334};
335
336}
337