1/*
2 * Copyright (C) 2004, 2005 Nikolas Zimmermann <zimmermann@kde.org>
3 * Copyright (C) 2004, 2005, 2006 Rob Buis <buis@kde.org>
4 * Copyright (C) 2008-2019 Apple Inc. All rights reserved.
5 * Copyright (C) Research In Motion Limited 2011. All rights reserved.
6 * Copyright (C) 2014 Adobe Systems Incorporated. All rights reserved.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24#include "config.h"
25#include "SVGAnimateElementBase.h"
26
27#include "QualifiedName.h"
28#include "SVGAttributeAnimator.h"
29#include "SVGElement.h"
30#include "SVGNames.h"
31#include <wtf/IsoMallocInlines.h>
32
33namespace WebCore {
34
35WTF_MAKE_ISO_ALLOCATED_IMPL(SVGAnimateElementBase);
36
37SVGAnimateElementBase::SVGAnimateElementBase(const QualifiedName& tagName, Document& document)
38 : SVGAnimationElement(tagName, document)
39{
40 ASSERT(hasTagName(SVGNames::animateTag)
41 || hasTagName(SVGNames::setTag)
42 || hasTagName(SVGNames::animateColorTag)
43 || hasTagName(SVGNames::animateTransformTag));
44}
45
46SVGAttributeAnimator* SVGAnimateElementBase::animator() const
47{
48 ASSERT(targetElement());
49 ASSERT(!hasInvalidCSSAttributeType());
50
51 if (!m_animator)
52 m_animator = targetElement()->createAnimator(attributeName(), animationMode(), calcMode(), isAccumulated(), isAdditive());
53
54 return m_animator.get();
55}
56
57bool SVGAnimateElementBase::hasValidAttributeType() const
58{
59 if (!targetElement() || hasInvalidCSSAttributeType())
60 return false;
61
62 return targetElement()->isAnimatedAttribute(attributeName());
63}
64
65bool SVGAnimateElementBase::hasInvalidCSSAttributeType() const
66{
67 if (!targetElement())
68 return false;
69
70 if (!m_hasInvalidCSSAttributeType)
71 m_hasInvalidCSSAttributeType = hasValidAttributeName() && attributeType() == AttributeType::CSS && !isTargetAttributeCSSProperty(targetElement(), attributeName());
72
73 return m_hasInvalidCSSAttributeType.value();
74}
75
76bool SVGAnimateElementBase::isDiscreteAnimator() const
77{
78 return hasValidAttributeType() && animatorIfExists() && animatorIfExists()->isDiscrete();
79}
80
81void SVGAnimateElementBase::setTargetElement(SVGElement* target)
82{
83 SVGAnimationElement::setTargetElement(target);
84 resetAnimation();
85}
86
87void SVGAnimateElementBase::setAttributeName(const QualifiedName& attributeName)
88{
89 SVGSMILElement::setAttributeName(attributeName);
90 resetAnimation();
91}
92
93void SVGAnimateElementBase::resetAnimation()
94{
95 SVGAnimationElement::resetAnimation();
96 m_animator = nullptr;
97 m_hasInvalidCSSAttributeType = { };
98}
99
100bool SVGAnimateElementBase::calculateFromAndToValues(const String& fromString, const String& toString)
101{
102 if (!targetElement())
103 return false;
104
105 if (auto* animator = this->animator()) {
106 animator->setFromAndToValues(targetElement(), animateRangeString(fromString), animateRangeString(toString));
107 return true;
108 }
109 return false;
110}
111
112bool SVGAnimateElementBase::calculateFromAndByValues(const String& fromString, const String& byString)
113{
114 if (!this->targetElement())
115 return false;
116
117 if (animationMode() == AnimationMode::By && (!isAdditive() || isDiscreteAnimator()))
118 return false;
119
120 if (animationMode() == AnimationMode::FromBy && isDiscreteAnimator())
121 return false;
122
123 if (auto* animator = this->animator()) {
124 animator->setFromAndByValues(targetElement(), animateRangeString(fromString), animateRangeString(byString));
125 return true;
126 }
127 return false;
128}
129
130bool SVGAnimateElementBase::calculateToAtEndOfDurationValue(const String& toAtEndOfDurationString)
131{
132 if (!targetElement() || toAtEndOfDurationString.isEmpty())
133 return false;
134
135 if (isDiscreteAnimator())
136 return true;
137
138 if (auto* animator = this->animator()) {
139 animator->setToAtEndOfDurationValue(animateRangeString(toAtEndOfDurationString));
140 return true;
141 }
142 return false;
143}
144
145void SVGAnimateElementBase::resetAnimatedType()
146{
147 if (!targetElement())
148 return;
149
150 if (auto* animator = this->animator())
151 animator->start(targetElement());
152}
153
154void SVGAnimateElementBase::calculateAnimatedValue(float progress, unsigned repeatCount, SVGSMILElement*)
155{
156 if (!targetElement())
157 return;
158
159 ASSERT(progress >= 0 && progress <= 1);
160 if (hasTagName(SVGNames::setTag))
161 progress = 1;
162
163 if (calcMode() == CalcMode::Discrete)
164 progress = progress < 0.5 ? 0 : 1;
165
166 if (auto* animator = this->animator())
167 animator->animate(targetElement(), progress, repeatCount);
168}
169
170void SVGAnimateElementBase::applyResultsToTarget()
171{
172 if (!targetElement())
173 return;
174
175 if (auto* animator = this->animator())
176 animator->apply(targetElement());
177}
178
179void SVGAnimateElementBase::clearAnimatedType(SVGElement* targetElement)
180{
181 if (!targetElement)
182 return;
183
184 if (auto* animator = this->animatorIfExists())
185 animator->stop(targetElement);
186}
187
188Optional<float> SVGAnimateElementBase::calculateDistance(const String& fromString, const String& toString)
189{
190 // FIXME: A return value of float is not enough to support paced animations on lists.
191 if (!targetElement())
192 return { };
193
194 if (auto* animator = this->animator())
195 return animator->calculateDistance(targetElement(), fromString, toString);
196
197 return { };
198}
199
200} // namespace WebCore
201