1 /* 2 * Copyright (C) 2013 Google 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 are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 G* * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #ifndef SVGAnimatedProperty_h 32 #define SVGAnimatedProperty_h 33 34 #include "bindings/core/v8/ExceptionStatePlaceholder.h" 35 #include "bindings/core/v8/ScriptWrappable.h" 36 #include "core/dom/ExceptionCode.h" 37 #include "core/svg/SVGParsingError.h" 38 #include "core/svg/properties/SVGPropertyInfo.h" 39 #include "core/svg/properties/SVGPropertyTearOff.h" 40 #include "wtf/Noncopyable.h" 41 #include "wtf/PassRefPtr.h" 42 #include "wtf/RefCounted.h" 43 44 namespace blink { 45 46 class SVGElement; 47 48 class SVGAnimatedPropertyBase : public RefCounted<SVGAnimatedPropertyBase>, public ScriptWrappableBase { 49 public: 50 virtual ~SVGAnimatedPropertyBase(); 51 52 virtual SVGPropertyBase* currentValueBase() = 0; 53 virtual bool isAnimating() const = 0; 54 55 virtual PassRefPtr<SVGPropertyBase> createAnimatedValue() = 0; 56 virtual void setAnimatedValue(PassRefPtr<SVGPropertyBase>) = 0; 57 virtual void animationEnded(); 58 59 virtual void setBaseValueAsString(const String& value, SVGParsingError& parseError) = 0; 60 virtual bool needsSynchronizeAttribute() = 0; 61 virtual void synchronizeAttribute(); 62 type()63 AnimatedPropertyType type() const 64 { 65 return m_type; 66 } 67 contextElement()68 SVGElement* contextElement() const 69 { 70 return m_contextElement; 71 } 72 attributeName()73 const QualifiedName& attributeName() const 74 { 75 return m_attributeName; 76 } 77 isReadOnly()78 bool isReadOnly() const 79 { 80 return m_isReadOnly; 81 } 82 setReadOnly()83 void setReadOnly() 84 { 85 m_isReadOnly = true; 86 } 87 88 bool isSpecified() const; 89 90 protected: 91 SVGAnimatedPropertyBase(AnimatedPropertyType, SVGElement*, const QualifiedName& attributeName); 92 93 private: 94 const AnimatedPropertyType m_type; 95 bool m_isReadOnly; 96 97 // This reference is kept alive from V8 wrapper 98 SVGElement* m_contextElement; 99 100 const QualifiedName& m_attributeName; 101 102 WTF_MAKE_NONCOPYABLE(SVGAnimatedPropertyBase); 103 }; 104 105 template <typename Property> 106 class SVGAnimatedPropertyCommon : public SVGAnimatedPropertyBase { 107 public: baseValue()108 Property* baseValue() 109 { 110 return m_baseValue.get(); 111 } 112 currentValue()113 Property* currentValue() 114 { 115 return m_currentValue ? m_currentValue.get() : m_baseValue.get(); 116 } 117 currentValue()118 const Property* currentValue() const 119 { 120 return const_cast<SVGAnimatedPropertyCommon*>(this)->currentValue(); 121 } 122 currentValueBase()123 virtual SVGPropertyBase* currentValueBase() OVERRIDE 124 { 125 return currentValue(); 126 } 127 isAnimating()128 virtual bool isAnimating() const OVERRIDE 129 { 130 return m_currentValue; 131 } 132 setBaseValueAsString(const String & value,SVGParsingError & parseError)133 void setBaseValueAsString(const String& value, SVGParsingError& parseError) OVERRIDE 134 { 135 TrackExceptionState es; 136 137 m_baseValue->setValueAsString(value, es); 138 139 if (es.hadException()) 140 parseError = ParsingAttributeFailedError; 141 } 142 createAnimatedValue()143 virtual PassRefPtr<SVGPropertyBase> createAnimatedValue() OVERRIDE 144 { 145 return m_baseValue->clone(); 146 } 147 setAnimatedValue(PassRefPtr<SVGPropertyBase> passValue)148 virtual void setAnimatedValue(PassRefPtr<SVGPropertyBase> passValue) OVERRIDE 149 { 150 RefPtr<SVGPropertyBase> value = passValue; 151 ASSERT(value->type() == Property::classType()); 152 m_currentValue = static_pointer_cast<Property>(value.release()); 153 } 154 animationEnded()155 virtual void animationEnded() OVERRIDE 156 { 157 m_currentValue.clear(); 158 159 SVGAnimatedPropertyBase::animationEnded(); 160 } 161 162 protected: SVGAnimatedPropertyCommon(SVGElement * contextElement,const QualifiedName & attributeName,PassRefPtr<Property> initialValue)163 SVGAnimatedPropertyCommon(SVGElement* contextElement, const QualifiedName& attributeName, PassRefPtr<Property> initialValue) 164 : SVGAnimatedPropertyBase(Property::classType(), contextElement, attributeName) 165 , m_baseValue(initialValue) 166 { 167 } 168 169 private: 170 RefPtr<Property> m_baseValue; 171 RefPtr<Property> m_currentValue; 172 }; 173 174 // Implementation of SVGAnimatedProperty which uses primitive types. 175 // This is for classes which return primitive type for its "animVal". 176 // Examples are SVGAnimatedBoolean, SVGAnimatedNumber, etc. 177 template <typename Property, typename TearOffType = typename Property::TearOffType, typename PrimitiveType = typename Property::PrimitiveType> 178 class SVGAnimatedProperty : public SVGAnimatedPropertyCommon<Property> { 179 public: needsSynchronizeAttribute()180 virtual bool needsSynchronizeAttribute() OVERRIDE 181 { 182 // DOM attribute synchronization is only needed if tear-off is being touched from javascript or the property is being animated. 183 // This prevents unnecessary attribute creation on target element. 184 return m_baseValueUpdated || this->isAnimating(); 185 } 186 synchronizeAttribute()187 virtual void synchronizeAttribute() OVERRIDE 188 { 189 SVGAnimatedPropertyBase::synchronizeAttribute(); 190 m_baseValueUpdated = false; 191 } 192 193 // SVGAnimated* DOM Spec implementations: 194 195 // baseVal()/setBaseVal()/animVal() are only to be used from SVG DOM implementation. 196 // Use currentValue() from C++ code. baseVal()197 PrimitiveType baseVal() 198 { 199 return this->baseValue()->value(); 200 } 201 setBaseVal(PrimitiveType value,blink::ExceptionState & exceptionState)202 void setBaseVal(PrimitiveType value, blink::ExceptionState& exceptionState) 203 { 204 if (this->isReadOnly()) { 205 exceptionState.throwDOMException(NoModificationAllowedError, "The attribute is read-only."); 206 return; 207 } 208 209 this->baseValue()->setValue(value); 210 m_baseValueUpdated = true; 211 212 ASSERT(this->attributeName() != QualifiedName::null()); 213 this->contextElement()->invalidateSVGAttributes(); 214 this->contextElement()->svgAttributeChanged(this->attributeName()); 215 } 216 animVal()217 PrimitiveType animVal() 218 { 219 return this->currentValue()->value(); 220 } 221 222 protected: SVGAnimatedProperty(SVGElement * contextElement,const QualifiedName & attributeName,PassRefPtr<Property> initialValue)223 SVGAnimatedProperty(SVGElement* contextElement, const QualifiedName& attributeName, PassRefPtr<Property> initialValue) 224 : SVGAnimatedPropertyCommon<Property>(contextElement, attributeName, initialValue) 225 , m_baseValueUpdated(false) 226 { 227 } 228 229 bool m_baseValueUpdated; 230 }; 231 232 // Implementation of SVGAnimatedProperty which uses tear-off value types. 233 // These classes has "void" for its PrimitiveType. 234 // This is for classes which return special type for its "animVal". 235 // Examples are SVGAnimatedLength, SVGAnimatedRect, SVGAnimated*List, etc. 236 template <typename Property, typename TearOffType> 237 class SVGAnimatedProperty<Property, TearOffType, void> : public SVGAnimatedPropertyCommon<Property> { 238 public: create(SVGElement * contextElement,const QualifiedName & attributeName,PassRefPtr<Property> initialValue)239 static PassRefPtr<SVGAnimatedProperty<Property> > create(SVGElement* contextElement, const QualifiedName& attributeName, PassRefPtr<Property> initialValue) 240 { 241 return adoptRef(new SVGAnimatedProperty<Property>(contextElement, attributeName, initialValue)); 242 } 243 setAnimatedValue(PassRefPtr<SVGPropertyBase> value)244 virtual void setAnimatedValue(PassRefPtr<SVGPropertyBase> value) OVERRIDE 245 { 246 SVGAnimatedPropertyCommon<Property>::setAnimatedValue(value); 247 updateAnimValTearOffIfNeeded(); 248 } 249 animationEnded()250 virtual void animationEnded() OVERRIDE 251 { 252 SVGAnimatedPropertyCommon<Property>::animationEnded(); 253 updateAnimValTearOffIfNeeded(); 254 } 255 needsSynchronizeAttribute()256 virtual bool needsSynchronizeAttribute() OVERRIDE 257 { 258 // DOM attribute synchronization is only needed if tear-off is being touched from javascript or the property is being animated. 259 // This prevents unnecessary attribute creation on target element. 260 return m_baseValTearOff || this->isAnimating(); 261 } 262 263 // SVGAnimated* DOM Spec implementations: 264 265 // baseVal()/animVal() are only to be used from SVG DOM implementation. 266 // Use currentValue() from C++ code. baseVal()267 virtual TearOffType* baseVal() 268 { 269 if (!m_baseValTearOff) { 270 m_baseValTearOff = TearOffType::create(this->baseValue(), this->contextElement(), PropertyIsNotAnimVal, this->attributeName()); 271 if (this->isReadOnly()) 272 m_baseValTearOff->setIsReadOnlyProperty(); 273 } 274 275 return m_baseValTearOff.get(); 276 } 277 animVal()278 TearOffType* animVal() 279 { 280 if (!m_animValTearOff) 281 m_animValTearOff = TearOffType::create(this->currentValue(), this->contextElement(), PropertyIsAnimVal, this->attributeName()); 282 283 return m_animValTearOff.get(); 284 } 285 286 protected: SVGAnimatedProperty(SVGElement * contextElement,const QualifiedName & attributeName,PassRefPtr<Property> initialValue)287 SVGAnimatedProperty(SVGElement* contextElement, const QualifiedName& attributeName, PassRefPtr<Property> initialValue) 288 : SVGAnimatedPropertyCommon<Property>(contextElement, attributeName, initialValue) 289 { 290 } 291 292 private: updateAnimValTearOffIfNeeded()293 void updateAnimValTearOffIfNeeded() 294 { 295 if (m_animValTearOff) 296 m_animValTearOff->setTarget(this->currentValue()); 297 } 298 299 // When still (not animated): 300 // Both m_animValTearOff and m_baseValTearOff target m_baseValue. 301 // When animated: 302 // m_animValTearOff targets m_currentValue. 303 // m_baseValTearOff targets m_baseValue. 304 RefPtr<TearOffType> m_baseValTearOff; 305 RefPtr<TearOffType> m_animValTearOff; 306 }; 307 308 } 309 310 #endif // SVGAnimatedProperty_h 311