1 | /* |
2 | * Copyright (C) 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 "SVGAnimationAdditiveListFunction.h" |
29 | #include "SVGLengthList.h" |
30 | #include "SVGNumberList.h" |
31 | #include "SVGPointList.h" |
32 | #include "SVGTransformDistance.h" |
33 | #include "SVGTransformList.h" |
34 | |
35 | namespace WebCore { |
36 | |
37 | class SVGElement; |
38 | |
39 | class SVGAnimationLengthListFunction : public SVGAnimationAdditiveListFunction<SVGLengthList> { |
40 | using Base = SVGAnimationAdditiveListFunction<SVGLengthList>; |
41 | |
42 | public: |
43 | SVGAnimationLengthListFunction(AnimationMode animationMode, CalcMode calcMode, bool isAccumulated, bool isAdditive, SVGLengthMode lengthMode) |
44 | : Base(animationMode, calcMode, isAccumulated, isAdditive, lengthMode) |
45 | { |
46 | } |
47 | |
48 | void setFromAndToValues(SVGElement*, const String& from, const String& to) override |
49 | { |
50 | m_from->parse(from); |
51 | m_to->parse(to); |
52 | } |
53 | |
54 | void setToAtEndOfDurationValue(const String& toAtEndOfDuration) override |
55 | { |
56 | m_toAtEndOfDuration->parse(toAtEndOfDuration); |
57 | } |
58 | |
59 | void animate(SVGElement* targetElement, float progress, unsigned repeatCount, RefPtr<SVGLengthList>& animated) |
60 | { |
61 | if (!adjustAnimatedList(m_animationMode, progress, animated)) |
62 | return; |
63 | |
64 | const Vector<Ref<SVGLength>>& fromItems = m_animationMode == AnimationMode::To ? animated->items() : m_from->items(); |
65 | const Vector<Ref<SVGLength>>& toItems = m_to->items(); |
66 | const Vector<Ref<SVGLength>>& toAtEndOfDurationItems = toAtEndOfDuration()->items(); |
67 | Vector<Ref<SVGLength>>& animatedItems = animated->items(); |
68 | SVGLengthMode lengthMode = animated->lengthMode(); |
69 | |
70 | SVGLengthContext lengthContext(targetElement); |
71 | for (unsigned i = 0; i < toItems.size(); ++i) { |
72 | SVGLengthType unitType = (i < fromItems.size() && progress < 0.5 ? fromItems : toItems)[i]->value().unitType(); |
73 | |
74 | float from = i < fromItems.size() ? fromItems[i]->value().value(lengthContext) : 0; |
75 | float to = toItems[i]->value().value(lengthContext); |
76 | float toAtEndOfDuration = i < toAtEndOfDurationItems.size() ? toAtEndOfDurationItems[i]->value().value(lengthContext) : 0; |
77 | float value = animatedItems[i]->value().value(lengthContext); |
78 | |
79 | value = Base::animate(progress, repeatCount, from, to, toAtEndOfDuration, value); |
80 | animatedItems[i]->value().setValue(lengthContext, value, lengthMode, unitType); |
81 | } |
82 | } |
83 | |
84 | private: |
85 | void addFromAndToValues(SVGElement* targetElement) override |
86 | { |
87 | const Vector<Ref<SVGLength>>& fromItems = m_from->items(); |
88 | const Vector<Ref<SVGLength>>& toItems = m_to->items(); |
89 | |
90 | if (!fromItems.size() || fromItems.size() != toItems.size()) |
91 | return; |
92 | |
93 | SVGLengthContext lengthContext(targetElement); |
94 | for (unsigned i = 0; i < fromItems.size(); ++i) { |
95 | const SVGLengthValue& fromValue = fromItems[i]->value(); |
96 | SVGLengthValue& toValue = toItems[i]->value(); |
97 | toValue.setValue(toValue.value(lengthContext) + fromValue.value(lengthContext), lengthContext); |
98 | } |
99 | } |
100 | }; |
101 | |
102 | class SVGAnimationNumberListFunction : public SVGAnimationAdditiveListFunction<SVGNumberList> { |
103 | public: |
104 | using Base = SVGAnimationAdditiveListFunction<SVGNumberList>; |
105 | using Base::Base; |
106 | |
107 | void setFromAndToValues(SVGElement*, const String& from, const String& to) override |
108 | { |
109 | m_from->parse(from); |
110 | m_to->parse(to); |
111 | } |
112 | |
113 | void setToAtEndOfDurationValue(const String& toAtEndOfDuration) override |
114 | { |
115 | m_toAtEndOfDuration->parse(toAtEndOfDuration); |
116 | } |
117 | |
118 | void animate(SVGElement*, float progress, unsigned repeatCount, RefPtr<SVGNumberList>& animated) |
119 | { |
120 | if (!adjustAnimatedList(m_animationMode, progress, animated)) |
121 | return; |
122 | |
123 | auto& fromItems = m_animationMode == AnimationMode::To ? animated->items() : m_from->items(); |
124 | auto& toItems = m_to->items(); |
125 | auto& toAtEndOfDurationItems = toAtEndOfDuration()->items(); |
126 | auto& animatedItems = animated->items(); |
127 | |
128 | for (unsigned i = 0; i < toItems.size(); ++i) { |
129 | float from = i < fromItems.size() ? fromItems[i]->value() : 0; |
130 | float to = toItems[i]->value(); |
131 | float toAtEndOfDuration = i < toAtEndOfDurationItems.size() ? toAtEndOfDurationItems[i]->value() : 0; |
132 | |
133 | float& value = animatedItems[i]->value(); |
134 | value = Base::animate(progress, repeatCount, from, to, toAtEndOfDuration, value); |
135 | } |
136 | } |
137 | |
138 | private: |
139 | void addFromAndToValues(SVGElement*) override |
140 | { |
141 | const Vector<Ref<SVGNumber>>& fromItems = m_from->items(); |
142 | Vector<Ref<SVGNumber>>& toItems = m_to->items(); |
143 | |
144 | if (!fromItems.size() || fromItems.size() != toItems.size()) |
145 | return; |
146 | |
147 | for (unsigned i = 0; i < fromItems.size(); ++i) |
148 | toItems[i]->setValue(fromItems[i]->value() + toItems[i]->value()); |
149 | } |
150 | }; |
151 | |
152 | class SVGAnimationPointListFunction : public SVGAnimationAdditiveListFunction<SVGPointList> { |
153 | public: |
154 | using Base = SVGAnimationAdditiveListFunction<SVGPointList>; |
155 | using Base::Base; |
156 | |
157 | void setFromAndToValues(SVGElement*, const String& from, const String& to) override |
158 | { |
159 | m_from->parse(from); |
160 | m_to->parse(to); |
161 | } |
162 | |
163 | void setToAtEndOfDurationValue(const String& toAtEndOfDuration) override |
164 | { |
165 | m_toAtEndOfDuration->parse(toAtEndOfDuration); |
166 | } |
167 | |
168 | void animate(SVGElement*, float progress, unsigned repeatCount, RefPtr<SVGPointList>& animated) |
169 | { |
170 | if (!adjustAnimatedList(m_animationMode, progress, animated)) |
171 | return; |
172 | |
173 | auto& fromItems = m_animationMode == AnimationMode::To ? animated->items() : m_from->items(); |
174 | auto& toItems = m_to->items(); |
175 | auto& toAtEndOfDurationItems = toAtEndOfDuration()->items(); |
176 | auto& animatedItems = animated->items(); |
177 | |
178 | for (unsigned i = 0; i < toItems.size(); ++i) { |
179 | FloatPoint from = i < fromItems.size() ? fromItems[i]->value() : FloatPoint(); |
180 | FloatPoint to = toItems[i]->value(); |
181 | FloatPoint toAtEndOfDuration = i < toAtEndOfDurationItems.size() ? toAtEndOfDurationItems[i]->value() : FloatPoint(); |
182 | FloatPoint& animated = animatedItems[i]->value(); |
183 | |
184 | float animatedX = Base::animate(progress, repeatCount, from.x(), to.x(), toAtEndOfDuration.x(), animated.x()); |
185 | float animatedY = Base::animate(progress, repeatCount, from.y(), to.y(), toAtEndOfDuration.y(), animated.y()); |
186 | |
187 | animated = { animatedX, animatedY }; |
188 | } |
189 | } |
190 | |
191 | private: |
192 | void addFromAndToValues(SVGElement*) override |
193 | { |
194 | const Vector<Ref<SVGPoint>>& fromItems = m_from->items(); |
195 | Vector<Ref<SVGPoint>>& toItems = m_to->items(); |
196 | |
197 | if (!fromItems.size() || fromItems.size() != toItems.size()) |
198 | return; |
199 | |
200 | for (unsigned i = 0; i < fromItems.size(); ++i) |
201 | toItems[i]->setValue(fromItems[i]->value() + toItems[i]->value()); |
202 | } |
203 | }; |
204 | |
205 | class SVGAnimationTransformListFunction : public SVGAnimationAdditiveListFunction<SVGTransformList> { |
206 | public: |
207 | using Base = SVGAnimationAdditiveListFunction<SVGTransformList>; |
208 | using Base::Base; |
209 | |
210 | void setFromAndToValues(SVGElement*, const String& from, const String& to) override |
211 | { |
212 | m_from->parse(from); |
213 | m_to->parse(to); |
214 | } |
215 | |
216 | void setToAtEndOfDurationValue(const String& toAtEndOfDuration) override |
217 | { |
218 | m_toAtEndOfDuration->parse(toAtEndOfDuration); |
219 | } |
220 | |
221 | void animate(SVGElement*, float progress, unsigned repeatCount, RefPtr<SVGTransformList>& animated) |
222 | { |
223 | // Pass false to 'resizeAnimatedIfNeeded', as the special post-multiplication behavior of <animateTransform> needs to be respected below. |
224 | if (!adjustAnimatedList(m_animationMode, progress, animated, false)) |
225 | return; |
226 | |
227 | // Spec: To animations provide specific functionality to get a smooth change from the underlying |
228 | // value to the âtoâ attribute value, which conflicts mathematically with the requirement for |
229 | // additive transform animations to be post-multiplied. As a consequence, in SVG 1.1 the behavior |
230 | // of to animations for âanimateTransformâ is undefined. |
231 | const Vector<Ref<SVGTransform>>& fromItems = m_from->items(); |
232 | const Vector<Ref<SVGTransform>>& toItems = m_to->items(); |
233 | const Vector<Ref<SVGTransform>>& toAtEndOfDurationItems = toAtEndOfDuration()->items(); |
234 | Vector<Ref<SVGTransform>>& animatedItems = animated->items(); |
235 | |
236 | // Never resize the animatedList to the m_to size, instead either clear the list |
237 | // or append to it. |
238 | if (!animatedItems.isEmpty() && (!m_isAdditive || m_animationMode == AnimationMode::To)) |
239 | animatedItems.clear(); |
240 | |
241 | auto fromItemsSize = fromItems.size(); |
242 | |
243 | static const AffineTransform zerosAffineTransform = { 0, 0, 0, 0, 0, 0 }; |
244 | const SVGTransformValue& to = toItems[0]->value(); |
245 | const SVGTransformValue zerosTransform = SVGTransformValue(to.type(), zerosAffineTransform); |
246 | |
247 | const SVGTransformValue& from = fromItemsSize ? fromItems[0]->value() : zerosTransform; |
248 | SVGTransformValue current = SVGTransformDistance(from, to).scaledDistance(progress).addToSVGTransform(from); |
249 | |
250 | if (m_isAccumulated && repeatCount) { |
251 | const SVGTransformValue& toAtEndOfDuration = toAtEndOfDurationItems.size() ? toAtEndOfDurationItems[0]->value() : zerosTransform; |
252 | animatedItems.append(SVGTransform::create(SVGTransformDistance::addSVGTransforms(current, toAtEndOfDuration, repeatCount))); |
253 | } else |
254 | animatedItems.append(SVGTransform::create(current)); |
255 | } |
256 | |
257 | private: |
258 | void addFromAndToValues(SVGElement*) override |
259 | { |
260 | const Vector<Ref<SVGTransform>>& fromItems = m_from->items(); |
261 | Vector<Ref<SVGTransform>>& toItems = m_to->items(); |
262 | |
263 | if (!fromItems.size() || fromItems.size() != toItems.size()) |
264 | return; |
265 | |
266 | ASSERT(fromItems.size() == 1); |
267 | const Ref<SVGTransform>& from = fromItems[0]; |
268 | Ref<SVGTransform>& to = toItems[0]; |
269 | |
270 | to->setValue(SVGTransformDistance::addSVGTransforms(from->value(), to->value())); |
271 | } |
272 | }; |
273 | |
274 | } |
275 | |