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
35namespace WebCore {
36
37class SVGElement;
38
39class SVGAnimationLengthListFunction : public SVGAnimationAdditiveListFunction<SVGLengthList> {
40 using Base = SVGAnimationAdditiveListFunction<SVGLengthList>;
41
42public:
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
84private:
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
102class SVGAnimationNumberListFunction : public SVGAnimationAdditiveListFunction<SVGNumberList> {
103public:
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
138private:
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
152class SVGAnimationPointListFunction : public SVGAnimationAdditiveListFunction<SVGPointList> {
153public:
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
191private:
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
205class SVGAnimationTransformListFunction : public SVGAnimationAdditiveListFunction<SVGTransformList> {
206public:
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
257private:
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