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 "Color.h" |
29 | #include "FloatRect.h" |
30 | #include "SVGAngleValue.h" |
31 | #include "SVGAnimationAdditiveValueFunction.h" |
32 | #include "SVGLengthValue.h" |
33 | #include "SVGPathByteStream.h" |
34 | #include "SVGPropertyTraits.h" |
35 | |
36 | namespace WebCore { |
37 | |
38 | class SVGAnimationAngleFunction : public SVGAnimationAdditiveValueFunction<SVGAngleValue> { |
39 | public: |
40 | using Base = SVGAnimationAdditiveValueFunction<SVGAngleValue>; |
41 | using Base::Base; |
42 | |
43 | void setFromAndToValues(SVGElement*, const String&, const String&) override |
44 | { |
45 | // Values will be set by SVGAnimatedAngleOrientAnimator. |
46 | ASSERT_NOT_REACHED(); |
47 | } |
48 | |
49 | void animate(SVGElement*, float progress, unsigned repeatCount, SVGAngleValue& animated) |
50 | { |
51 | float number = animated.value(); |
52 | number = Base::animate(progress, repeatCount, m_from.value(), m_to.value(), toAtEndOfDuration().value(), number); |
53 | animated.setValue(number); |
54 | } |
55 | |
56 | private: |
57 | friend class SVGAnimatedAngleOrientAnimator; |
58 | |
59 | void addFromAndToValues(SVGElement*) override |
60 | { |
61 | m_to.setValue(m_to.value() + m_from.value()); |
62 | } |
63 | }; |
64 | |
65 | class SVGAnimationColorFunction : public SVGAnimationAdditiveValueFunction<Color> { |
66 | public: |
67 | using Base = SVGAnimationAdditiveValueFunction<Color>; |
68 | using Base::Base; |
69 | |
70 | void setFromAndToValues(SVGElement* targetElement, const String& from, const String& to) override |
71 | { |
72 | m_from = colorFromString(targetElement, from); |
73 | m_to = colorFromString(targetElement, to); |
74 | } |
75 | |
76 | void setToAtEndOfDurationValue(const String& toAtEndOfDuration) override |
77 | { |
78 | m_toAtEndOfDuration = SVGPropertyTraits<Color>::fromString(toAtEndOfDuration); |
79 | } |
80 | |
81 | void animate(SVGElement*, float progress, unsigned repeatCount, Color& animated) |
82 | { |
83 | Color from = m_animationMode == AnimationMode::To ? animated : m_from; |
84 | |
85 | float red = Base::animate(progress, repeatCount, from.red(), m_to.red(), toAtEndOfDuration().red(), animated.red()); |
86 | float green = Base::animate(progress, repeatCount, from.green(), m_to.green(), toAtEndOfDuration().green(), animated.green()); |
87 | float blue = Base::animate(progress, repeatCount, from.blue(), m_to.blue(), toAtEndOfDuration().blue(), animated.blue()); |
88 | float alpha = Base::animate(progress, repeatCount, from.alpha(), m_to.alpha(), toAtEndOfDuration().alpha(), animated.alpha()); |
89 | |
90 | animated = { roundAndClampColorChannel(red), roundAndClampColorChannel(green), roundAndClampColorChannel(blue), roundAndClampColorChannel(alpha) }; |
91 | } |
92 | |
93 | Optional<float> calculateDistance(SVGElement*, const String& from, const String& to) const override |
94 | { |
95 | Color fromColor = CSSParser::parseColor(from.stripWhiteSpace()); |
96 | if (!fromColor.isValid()) |
97 | return { }; |
98 | Color toColor = CSSParser::parseColor(to.stripWhiteSpace()); |
99 | if (!toColor.isValid()) |
100 | return { }; |
101 | float red = fromColor.red() - toColor.red(); |
102 | float green = fromColor.green() - toColor.green(); |
103 | float blue = fromColor.blue() - toColor.blue(); |
104 | return sqrtf(red * red + green * green + blue * blue); |
105 | } |
106 | |
107 | private: |
108 | void addFromAndToValues(SVGElement*) override |
109 | { |
110 | // Ignores any alpha and sets alpha on result to 100% opaque. |
111 | m_to = { |
112 | roundAndClampColorChannel(m_to.red() + m_from.red()), |
113 | roundAndClampColorChannel(m_to.green() + m_from.green()), |
114 | roundAndClampColorChannel(m_to.blue() + m_from.blue()) |
115 | }; |
116 | } |
117 | |
118 | static Color colorFromString(SVGElement*, const String&); |
119 | }; |
120 | |
121 | class SVGAnimationIntegerFunction : public SVGAnimationAdditiveValueFunction<int> { |
122 | friend class SVGAnimatedIntegerPairAnimator; |
123 | |
124 | public: |
125 | using Base = SVGAnimationAdditiveValueFunction<int>; |
126 | using Base::Base; |
127 | |
128 | void setFromAndToValues(SVGElement*, const String& from, const String& to) override |
129 | { |
130 | m_from = SVGPropertyTraits<int>::fromString(from); |
131 | m_to = SVGPropertyTraits<int>::fromString(to); |
132 | } |
133 | |
134 | void setToAtEndOfDurationValue(const String& toAtEndOfDuration) override |
135 | { |
136 | m_toAtEndOfDuration = SVGPropertyTraits<int>::fromString(toAtEndOfDuration); |
137 | } |
138 | |
139 | void animate(SVGElement*, float progress, unsigned repeatCount, int& animated) |
140 | { |
141 | animated = static_cast<int>(roundf(Base::animate(progress, repeatCount, m_from, m_to, toAtEndOfDuration(), animated))); |
142 | } |
143 | |
144 | Optional<float> calculateDistance(SVGElement*, const String& from, const String& to) const override |
145 | { |
146 | return std::abs(to.toIntStrict() - from.toIntStrict()); |
147 | } |
148 | |
149 | private: |
150 | void addFromAndToValues(SVGElement*) override |
151 | { |
152 | m_to += m_from; |
153 | } |
154 | }; |
155 | |
156 | class SVGAnimationLengthFunction : public SVGAnimationAdditiveValueFunction<SVGLengthValue> { |
157 | using Base = SVGAnimationAdditiveValueFunction<SVGLengthValue>; |
158 | |
159 | public: |
160 | SVGAnimationLengthFunction(AnimationMode animationMode, CalcMode calcMode, bool isAccumulated, bool isAdditive, SVGLengthMode lengthMode) |
161 | : Base(animationMode, calcMode, isAccumulated, isAdditive) |
162 | , m_lengthMode(lengthMode) |
163 | { |
164 | } |
165 | |
166 | void setFromAndToValues(SVGElement*, const String& from, const String& to) override |
167 | { |
168 | m_from = SVGLengthValue(m_lengthMode, from); |
169 | m_to = SVGLengthValue(m_lengthMode, to); |
170 | } |
171 | |
172 | void setToAtEndOfDurationValue(const String& toAtEndOfDuration) override |
173 | { |
174 | m_toAtEndOfDuration = SVGLengthValue(m_lengthMode, toAtEndOfDuration); |
175 | } |
176 | |
177 | void animate(SVGElement* targetElement, float progress, unsigned repeatCount, SVGLengthValue& animated) |
178 | { |
179 | SVGLengthContext lengthContext(targetElement); |
180 | SVGLengthType unitType = progress < 0.5 ? m_from.unitType() : m_to.unitType(); |
181 | |
182 | float from = (m_animationMode == AnimationMode::To ? animated : m_from).value(lengthContext); |
183 | float to = m_to.value(lengthContext); |
184 | float toAtEndOfDuration = this->toAtEndOfDuration().value(lengthContext); |
185 | float value = animated.value(lengthContext); |
186 | |
187 | value = Base::animate(progress, repeatCount, from, to, toAtEndOfDuration, value); |
188 | animated = { lengthContext, value, m_lengthMode, unitType }; |
189 | } |
190 | |
191 | Optional<float> calculateDistance(SVGElement* targetElement, const String& from, const String& to) const override |
192 | { |
193 | SVGLengthContext lengthContext(targetElement); |
194 | auto fromLength = SVGLengthValue(m_lengthMode, from); |
195 | auto toLength = SVGLengthValue(m_lengthMode, to); |
196 | return fabsf(toLength.value(lengthContext) - fromLength.value(lengthContext)); |
197 | } |
198 | |
199 | private: |
200 | void addFromAndToValues(SVGElement* targetElement) override |
201 | { |
202 | SVGLengthContext lengthContext(targetElement); |
203 | m_to.setValue(m_to.value(lengthContext) + m_from.value(lengthContext), lengthContext); |
204 | } |
205 | |
206 | SVGLengthMode m_lengthMode; |
207 | }; |
208 | |
209 | class SVGAnimationNumberFunction : public SVGAnimationAdditiveValueFunction<float> { |
210 | friend class SVGAnimatedNumberPairAnimator; |
211 | |
212 | public: |
213 | using Base = SVGAnimationAdditiveValueFunction<float>; |
214 | using Base::Base; |
215 | |
216 | void setFromAndToValues(SVGElement*, const String& from, const String& to) override |
217 | { |
218 | m_from = SVGPropertyTraits<float>::fromString(from); |
219 | m_to = SVGPropertyTraits<float>::fromString(to); |
220 | } |
221 | |
222 | void setToAtEndOfDurationValue(const String& toAtEndOfDuration) override |
223 | { |
224 | m_toAtEndOfDuration = SVGPropertyTraits<float>::fromString(toAtEndOfDuration); |
225 | } |
226 | |
227 | void animate(SVGElement*, float progress, unsigned repeatCount, float& animated) |
228 | { |
229 | float from = m_animationMode == AnimationMode::To ? animated : m_from; |
230 | animated = Base::animate(progress, repeatCount, from, m_to, toAtEndOfDuration(), animated); |
231 | } |
232 | |
233 | Optional<float> calculateDistance(SVGElement*, const String& from, const String& to) const override |
234 | { |
235 | float fromNumber = 0; |
236 | float toNumber = 0; |
237 | parseNumberFromString(from, fromNumber); |
238 | parseNumberFromString(to, toNumber); |
239 | return fabsf(toNumber - fromNumber); |
240 | } |
241 | |
242 | private: |
243 | void addFromAndToValues(SVGElement*) override |
244 | { |
245 | m_to += m_from; |
246 | } |
247 | }; |
248 | |
249 | class SVGAnimationPathSegListFunction : public SVGAnimationAdditiveValueFunction<SVGPathByteStream> { |
250 | public: |
251 | using Base = SVGAnimationAdditiveValueFunction<SVGPathByteStream>; |
252 | using Base::Base; |
253 | |
254 | void setFromAndToValues(SVGElement*, const String& from, const String& to) override |
255 | { |
256 | m_from = SVGPathByteStream(from); |
257 | m_to = SVGPathByteStream(to); |
258 | } |
259 | |
260 | void setToAtEndOfDurationValue(const String& toAtEndOfDuration) override |
261 | { |
262 | m_toAtEndOfDuration = SVGPathByteStream(toAtEndOfDuration); |
263 | } |
264 | |
265 | void animate(SVGElement*, float progress, unsigned repeatCount, SVGPathByteStream& animated) |
266 | { |
267 | SVGPathByteStream underlyingPath; |
268 | if (m_animationMode == AnimationMode::To) |
269 | underlyingPath = animated; |
270 | |
271 | const SVGPathByteStream& from = m_animationMode == AnimationMode::To ? underlyingPath : m_from; |
272 | |
273 | // Cache the current animated value before the buildAnimatedSVGPathByteStream() clears animatedPath. |
274 | SVGPathByteStream lastAnimated; |
275 | if (!from.size() || (m_isAdditive && m_animationMode != AnimationMode::To)) |
276 | lastAnimated = animated; |
277 | |
278 | buildAnimatedSVGPathByteStream(from, m_to, animated, progress); |
279 | |
280 | // Handle additive='sum'. |
281 | if (!lastAnimated.isEmpty()) |
282 | addToSVGPathByteStream(animated, lastAnimated); |
283 | |
284 | // Handle accumulate='sum'. |
285 | if (m_isAccumulated && repeatCount) |
286 | addToSVGPathByteStream(animated, toAtEndOfDuration(), repeatCount); |
287 | } |
288 | |
289 | private: |
290 | void addFromAndToValues(SVGElement*) override |
291 | { |
292 | if (!m_from.size() || m_from.size() != m_to.size()) |
293 | return; |
294 | addToSVGPathByteStream(m_to, m_from); |
295 | } |
296 | }; |
297 | |
298 | class SVGAnimationRectFunction : public SVGAnimationAdditiveValueFunction<FloatRect> { |
299 | public: |
300 | using Base = SVGAnimationAdditiveValueFunction<FloatRect>; |
301 | using Base::Base; |
302 | |
303 | void setFromAndToValues(SVGElement*, const String& from, const String& to) override |
304 | { |
305 | m_from = SVGPropertyTraits<FloatRect>::fromString(from); |
306 | m_to = SVGPropertyTraits<FloatRect>::fromString(to); |
307 | } |
308 | |
309 | void setToAtEndOfDurationValue(const String& toAtEndOfDuration) override |
310 | { |
311 | m_toAtEndOfDuration = SVGPropertyTraits<FloatRect>::fromString(toAtEndOfDuration); |
312 | } |
313 | |
314 | void animate(SVGElement*, float progress, unsigned repeatCount, FloatRect& animated) |
315 | { |
316 | FloatRect from = m_animationMode == AnimationMode::To ? animated : m_from; |
317 | |
318 | float x = Base::animate(progress, repeatCount, from.x(), m_to.x(), toAtEndOfDuration().x(), animated.x()); |
319 | float y = Base::animate(progress, repeatCount, from.y(), m_to.y(), toAtEndOfDuration().y(), animated.y()); |
320 | float width = Base::animate(progress, repeatCount, from.width(), m_to.width(), toAtEndOfDuration().width(), animated.width()); |
321 | float height = Base::animate(progress, repeatCount, from.height(), m_to.height(), toAtEndOfDuration().height(), animated.height()); |
322 | |
323 | animated = { x, y, width, height }; |
324 | } |
325 | |
326 | private: |
327 | void addFromAndToValues(SVGElement*) override |
328 | { |
329 | m_to += m_from; |
330 | } |
331 | }; |
332 | |
333 | } |
334 | |