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/css/parser/CSSParser.h" 25 #include "core/svg/SVGAnimateTransformElement.h" 26 #include "core/svg/SVGAnimatedColor.h" 27 #include "core/svg/SVGAnimationElement.h" 28 #include "core/svg/SVGElement.h" 29 #include "core/svg/SVGLength.h" 30 #include "core/svg/SVGLengthList.h" 31 #include "core/svg/SVGNumber.h" 32 #include "core/svg/SVGPointList.h" 33 #include "core/svg/SVGString.h" 34 #include "core/svg/SVGTransformList.h" 35 36 namespace blink { 37 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 60 SVGAnimatedTypeAnimator::~SVGAnimatedTypeAnimator() 61 { 62 } 63 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() : CSSParser::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 138 PassRefPtr<SVGPropertyBase> SVGAnimatedTypeAnimator::constructFromString(const String& value) 139 { 140 return createPropertyForAnimation(value); 141 } 142 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 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 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 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 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 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 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: 215 explicit ParsePropertyFromString(SVGAnimatedTypeAnimator* animator) 216 : m_animator(animator) 217 { 218 } 219 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 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 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 256 void SVGAnimatedTypeAnimator::trace(Visitor* visitor) 257 { 258 visitor->trace(m_animationElement); 259 visitor->trace(m_contextElement); 260 } 261 262 } 263