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 | |
34 | namespace WebCore { |
35 | |
36 | class SVGAttributeAnimator; |
37 | |
38 | template<typename OwnerType, typename... BaseTypes> |
39 | class SVGPropertyOwnerRegistry : public SVGPropertyRegistry { |
40 | public: |
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 | |
291 | private: |
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 | |