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 | |
33 | namespace WebCore { |
34 | |
35 | WTF_MAKE_ISO_ALLOCATED_IMPL(SVGAnimateElementBase); |
36 | |
37 | SVGAnimateElementBase::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 | |
46 | SVGAttributeAnimator* 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 | |
57 | bool SVGAnimateElementBase::hasValidAttributeType() const |
58 | { |
59 | if (!targetElement() || hasInvalidCSSAttributeType()) |
60 | return false; |
61 | |
62 | return targetElement()->isAnimatedAttribute(attributeName()); |
63 | } |
64 | |
65 | bool 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 | |
76 | bool SVGAnimateElementBase::isDiscreteAnimator() const |
77 | { |
78 | return hasValidAttributeType() && animatorIfExists() && animatorIfExists()->isDiscrete(); |
79 | } |
80 | |
81 | void SVGAnimateElementBase::setTargetElement(SVGElement* target) |
82 | { |
83 | SVGAnimationElement::setTargetElement(target); |
84 | resetAnimation(); |
85 | } |
86 | |
87 | void SVGAnimateElementBase::setAttributeName(const QualifiedName& attributeName) |
88 | { |
89 | SVGSMILElement::setAttributeName(attributeName); |
90 | resetAnimation(); |
91 | } |
92 | |
93 | void SVGAnimateElementBase::resetAnimation() |
94 | { |
95 | SVGAnimationElement::resetAnimation(); |
96 | m_animator = nullptr; |
97 | m_hasInvalidCSSAttributeType = { }; |
98 | } |
99 | |
100 | bool 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 | |
112 | bool 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 | |
130 | bool 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 | |
145 | void SVGAnimateElementBase::resetAnimatedType() |
146 | { |
147 | if (!targetElement()) |
148 | return; |
149 | |
150 | if (auto* animator = this->animator()) |
151 | animator->start(targetElement()); |
152 | } |
153 | |
154 | void 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 | |
170 | void SVGAnimateElementBase::applyResultsToTarget() |
171 | { |
172 | if (!targetElement()) |
173 | return; |
174 | |
175 | if (auto* animator = this->animator()) |
176 | animator->apply(targetElement()); |
177 | } |
178 | |
179 | void SVGAnimateElementBase::clearAnimatedType(SVGElement* targetElement) |
180 | { |
181 | if (!targetElement) |
182 | return; |
183 | |
184 | if (auto* animator = this->animatorIfExists()) |
185 | animator->stop(targetElement); |
186 | } |
187 | |
188 | Optional<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 | |