1 /*
2 * Copyright (C) Research In Motion Limited 2011-2012. All rights reserved.
3 * Copyright (C) 2013 Samsung Electronics. All rights reserved.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #include "config.h"
22 #include "core/svg/SVGAnimatedTypeAnimator.h"
23
24 #include "core/svg/SVGAnimateTransformElement.h"
25 #include "core/svg/SVGAnimatedColor.h"
26 #include "core/svg/SVGAnimationElement.h"
27 #include "core/svg/SVGElement.h"
28 #include "core/svg/SVGLength.h"
29 #include "core/svg/SVGLengthList.h"
30 #include "core/svg/SVGNumber.h"
31 #include "core/svg/SVGPaint.h"
32 #include "core/svg/SVGPointList.h"
33 #include "core/svg/SVGString.h"
34 #include "core/svg/SVGTransformList.h"
35
36 namespace WebCore {
37
SVGAnimatedTypeAnimator(SVGAnimationElement * animationElement,SVGElement * contextElement)38 SVGAnimatedTypeAnimator::SVGAnimatedTypeAnimator(SVGAnimationElement* animationElement, SVGElement* contextElement)
39 : m_animationElement(animationElement)
40 , m_contextElement(contextElement)
41 {
42 ASSERT(m_animationElement);
43 ASSERT(m_contextElement);
44
45 const QualifiedName& attributeName = m_animationElement->attributeName();
46 m_animatedProperty = m_contextElement->propertyFromAttribute(attributeName);
47 m_type = m_animatedProperty ? m_animatedProperty->type()
48 : SVGElement::animatedPropertyTypeForCSSAttribute(attributeName);
49
50 // Only <animateTransform> is allowed to animate AnimatedTransformList.
51 // http://www.w3.org/TR/SVG/animate.html#AnimationAttributesAndProperties
52 if (m_type == AnimatedTransformList && !isSVGAnimateTransformElement(*animationElement))
53 m_type = AnimatedUnknown;
54
55 ASSERT(m_type != AnimatedPoint
56 && m_type != AnimatedStringList
57 && m_type != AnimatedTransform);
58 }
59
~SVGAnimatedTypeAnimator()60 SVGAnimatedTypeAnimator::~SVGAnimatedTypeAnimator()
61 {
62 }
63
createPropertyForAnimation(const String & value)64 PassRefPtr<SVGPropertyBase> SVGAnimatedTypeAnimator::createPropertyForAnimation(const String& value)
65 {
66 if (isAnimatingSVGDom()) {
67 // SVG DOM animVal animation code-path.
68
69 if (m_type == AnimatedTransformList) {
70 // TransformList must be animated via <animateTransform>,
71 // and its {from,by,to} attribute values needs to be parsed w.r.t. its "type" attribute.
72 // Spec: http://www.w3.org/TR/SVG/single-page.html#animate-AnimateTransformElement
73 ASSERT(m_animationElement);
74 SVGTransformType transformType = toSVGAnimateTransformElement(m_animationElement)->transformType();
75 return SVGTransformList::create(transformType, value);
76 }
77
78 ASSERT(m_animatedProperty);
79 return m_animatedProperty->currentValueBase()->cloneForAnimation(value);
80 }
81
82 ASSERT(isAnimatingCSSProperty());
83
84 // CSS properties animation code-path.
85 // Create a basic instance of the corresponding SVG property.
86 // The instance will not have full context info. (e.g. SVGLengthMode)
87
88 switch (m_type) {
89 case AnimatedColor:
90 return SVGColorProperty::create(value.isEmpty() ? StyleColor::currentColor() : SVGPaint::colorFromRGBColorString(value));
91 case AnimatedNumber: {
92 RefPtr<SVGNumber> property = SVGNumber::create();
93 property->setValueAsString(value, IGNORE_EXCEPTION);
94 return property.release();
95 }
96 case AnimatedLength: {
97 RefPtr<SVGLength> property = SVGLength::create(LengthModeOther);
98 property->setValueAsString(value, IGNORE_EXCEPTION);
99 return property.release();
100 }
101 case AnimatedLengthList: {
102 RefPtr<SVGLengthList> property = SVGLengthList::create(LengthModeOther);
103 property->setValueAsString(value, IGNORE_EXCEPTION);
104 return property.release();
105 }
106 case AnimatedString: {
107 RefPtr<SVGString> property = SVGString::create();
108 property->setValueAsString(value, IGNORE_EXCEPTION);
109 return property.release();
110 }
111
112 // These types don't appear in the table in SVGElement::animatedPropertyTypeForCSSAttribute() and thus don't need support.
113 case AnimatedAngle:
114 case AnimatedBoolean:
115 case AnimatedEnumeration:
116 case AnimatedInteger:
117 case AnimatedIntegerOptionalInteger:
118 case AnimatedNumberList:
119 case AnimatedNumberOptionalNumber:
120 case AnimatedPath:
121 case AnimatedPoint:
122 case AnimatedPoints:
123 case AnimatedPreserveAspectRatio:
124 case AnimatedRect:
125 case AnimatedStringList:
126 case AnimatedTransform:
127 case AnimatedTransformList:
128 ASSERT_NOT_REACHED();
129
130 case AnimatedUnknown:
131 ASSERT_NOT_REACHED();
132 };
133
134 ASSERT_NOT_REACHED();
135 return nullptr;
136 }
137
constructFromString(const String & value)138 PassRefPtr<SVGPropertyBase> SVGAnimatedTypeAnimator::constructFromString(const String& value)
139 {
140 return createPropertyForAnimation(value);
141 }
142
calculateFromAndToValues(RefPtr<SVGPropertyBase> & from,RefPtr<SVGPropertyBase> & to,const String & fromString,const String & toString)143 void SVGAnimatedTypeAnimator::calculateFromAndToValues(RefPtr<SVGPropertyBase>& from, RefPtr<SVGPropertyBase>& to, const String& fromString, const String& toString)
144 {
145 from = constructFromString(fromString);
146 to = constructFromString(toString);
147 }
148
calculateFromAndByValues(RefPtr<SVGPropertyBase> & from,RefPtr<SVGPropertyBase> & to,const String & fromString,const String & byString)149 void SVGAnimatedTypeAnimator::calculateFromAndByValues(RefPtr<SVGPropertyBase>& from, RefPtr<SVGPropertyBase>& to, const String& fromString, const String& byString)
150 {
151 from = constructFromString(fromString);
152 to = constructFromString(byString);
153 // FIXME(oilpan): Below .get() should be removed after transition types are gone.
154 to->add(from.get(), m_contextElement);
155 }
156
157 namespace {
158
setAnimatedValueOnAllTargetProperties(const WillBeHeapVector<RawPtrWillBeMember<SVGElement>> & list,const QualifiedName & attributeName,PassRefPtr<SVGPropertyBase> passValue)159 void setAnimatedValueOnAllTargetProperties(const WillBeHeapVector<RawPtrWillBeMember<SVGElement> >& list, const QualifiedName& attributeName, PassRefPtr<SVGPropertyBase> passValue)
160 {
161 RefPtr<SVGPropertyBase> value = passValue;
162
163 WillBeHeapVector<RawPtrWillBeMember<SVGElement> >::const_iterator it = list.begin();
164 WillBeHeapVector<RawPtrWillBeMember<SVGElement> >::const_iterator itEnd = list.end();
165 for (; it != itEnd; ++it) {
166 RefPtr<SVGAnimatedPropertyBase> animatedProperty = (*it)->propertyFromAttribute(attributeName);
167 if (animatedProperty)
168 animatedProperty->setAnimatedValue(value);
169 }
170 }
171
172 }
173
resetAnimation(const WillBeHeapVector<RawPtrWillBeMember<SVGElement>> & list)174 PassRefPtr<SVGPropertyBase> SVGAnimatedTypeAnimator::resetAnimation(const WillBeHeapVector<RawPtrWillBeMember<SVGElement> >& list)
175 {
176 ASSERT(isAnimatingSVGDom());
177 RefPtr<SVGPropertyBase> animatedValue = m_animatedProperty->createAnimatedValue();
178 ASSERT(animatedValue->type() == m_type);
179 setAnimatedValueOnAllTargetProperties(list, m_animatedProperty->attributeName(), animatedValue);
180
181 return animatedValue.release();
182 }
183
startAnimValAnimation(const WillBeHeapVector<RawPtrWillBeMember<SVGElement>> & list)184 PassRefPtr<SVGPropertyBase> SVGAnimatedTypeAnimator::startAnimValAnimation(const WillBeHeapVector<RawPtrWillBeMember<SVGElement> >& list)
185 {
186 ASSERT(isAnimatingSVGDom());
187 SVGElement::InstanceUpdateBlocker blocker(m_contextElement);
188
189 return resetAnimation(list);
190 }
191
stopAnimValAnimation(const WillBeHeapVector<RawPtrWillBeMember<SVGElement>> & list)192 void SVGAnimatedTypeAnimator::stopAnimValAnimation(const WillBeHeapVector<RawPtrWillBeMember<SVGElement> >& list)
193 {
194 ASSERT(isAnimatingSVGDom());
195 SVGElement::InstanceUpdateBlocker blocker(m_contextElement);
196
197 WillBeHeapVector<RawPtrWillBeMember<SVGElement> >::const_iterator it = list.begin();
198 WillBeHeapVector<RawPtrWillBeMember<SVGElement> >::const_iterator itEnd = list.end();
199 for (; it != itEnd; ++it) {
200 RefPtr<SVGAnimatedPropertyBase> animatedProperty = (*it)->propertyFromAttribute(m_animatedProperty->attributeName());
201 if (animatedProperty)
202 animatedProperty->animationEnded();
203 }
204 }
205
resetAnimValToBaseVal(const WillBeHeapVector<RawPtrWillBeMember<SVGElement>> & list)206 PassRefPtr<SVGPropertyBase> SVGAnimatedTypeAnimator::resetAnimValToBaseVal(const WillBeHeapVector<RawPtrWillBeMember<SVGElement> >& list)
207 {
208 SVGElement::InstanceUpdateBlocker blocker(m_contextElement);
209
210 return resetAnimation(list);
211 }
212
213 class ParsePropertyFromString {
214 public:
ParsePropertyFromString(SVGAnimatedTypeAnimator * animator)215 explicit ParsePropertyFromString(SVGAnimatedTypeAnimator* animator)
216 : m_animator(animator)
217 {
218 }
219
operator ()(SVGAnimationElement *,const String & value)220 PassRefPtr<SVGPropertyBase> operator()(SVGAnimationElement*, const String& value)
221 {
222 return m_animator->createPropertyForAnimation(value);
223 }
224
225 private:
226 SVGAnimatedTypeAnimator* m_animator;
227 };
228
calculateAnimatedValue(float percentage,unsigned repeatCount,SVGPropertyBase * from,SVGPropertyBase * to,SVGPropertyBase * toAtEndOfDuration,SVGPropertyBase * animated)229 void SVGAnimatedTypeAnimator::calculateAnimatedValue(float percentage, unsigned repeatCount, SVGPropertyBase* from, SVGPropertyBase* to, SVGPropertyBase* toAtEndOfDuration, SVGPropertyBase* animated)
230 {
231 ASSERT(m_animationElement);
232 ASSERT(m_contextElement);
233
234 RefPtr<SVGPropertyBase> fromValue = m_animationElement->animationMode() == ToAnimation ? animated : from;
235 RefPtr<SVGPropertyBase> toValue = to;
236 RefPtr<SVGPropertyBase> toAtEndOfDurationValue = toAtEndOfDuration;
237 RefPtr<SVGPropertyBase> animatedValue = animated;
238
239 // Apply CSS inheritance rules.
240 ParsePropertyFromString parsePropertyFromString(this);
241 m_animationElement->adjustForInheritance<RefPtr<SVGPropertyBase>, ParsePropertyFromString>(parsePropertyFromString, m_animationElement->fromPropertyValueType(), fromValue, m_contextElement);
242 m_animationElement->adjustForInheritance<RefPtr<SVGPropertyBase>, ParsePropertyFromString>(parsePropertyFromString, m_animationElement->toPropertyValueType(), toValue, m_contextElement);
243
244 animatedValue->calculateAnimatedValue(m_animationElement, percentage, repeatCount, fromValue, toValue, toAtEndOfDurationValue, m_contextElement);
245 }
246
calculateDistance(const String & fromString,const String & toString)247 float SVGAnimatedTypeAnimator::calculateDistance(const String& fromString, const String& toString)
248 {
249 ASSERT(m_animationElement);
250 ASSERT(m_contextElement);
251 RefPtr<SVGPropertyBase> fromValue = createPropertyForAnimation(fromString);
252 RefPtr<SVGPropertyBase> toValue = createPropertyForAnimation(toString);
253 return fromValue->calculateDistance(toValue, m_contextElement);
254 }
255
trace(Visitor * visitor)256 void SVGAnimatedTypeAnimator::trace(Visitor* visitor)
257 {
258 visitor->trace(m_animationElement);
259 visitor->trace(m_contextElement);
260 }
261
262 }
263