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
36namespace WebCore {
37
38class SVGAnimationAngleFunction : public SVGAnimationAdditiveValueFunction<SVGAngleValue> {
39public:
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
56private:
57 friend class SVGAnimatedAngleOrientAnimator;
58
59 void addFromAndToValues(SVGElement*) override
60 {
61 m_to.setValue(m_to.value() + m_from.value());
62 }
63};
64
65class SVGAnimationColorFunction : public SVGAnimationAdditiveValueFunction<Color> {
66public:
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
107private:
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
121class SVGAnimationIntegerFunction : public SVGAnimationAdditiveValueFunction<int> {
122 friend class SVGAnimatedIntegerPairAnimator;
123
124public:
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
149private:
150 void addFromAndToValues(SVGElement*) override
151 {
152 m_to += m_from;
153 }
154};
155
156class SVGAnimationLengthFunction : public SVGAnimationAdditiveValueFunction<SVGLengthValue> {
157 using Base = SVGAnimationAdditiveValueFunction<SVGLengthValue>;
158
159public:
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
199private:
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
209class SVGAnimationNumberFunction : public SVGAnimationAdditiveValueFunction<float> {
210 friend class SVGAnimatedNumberPairAnimator;
211
212public:
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
242private:
243 void addFromAndToValues(SVGElement*) override
244 {
245 m_to += m_from;
246 }
247};
248
249class SVGAnimationPathSegListFunction : public SVGAnimationAdditiveValueFunction<SVGPathByteStream> {
250public:
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
289private:
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
298class SVGAnimationRectFunction : public SVGAnimationAdditiveValueFunction<FloatRect> {
299public:
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
326private:
327 void addFromAndToValues(SVGElement*) override
328 {
329 m_to += m_from;
330 }
331};
332
333}
334