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/v8/ExceptionStatePlaceholder.h" 35 #include "bindings/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 WebCore { 45 46 class SVGElement; 47 48 class SVGAnimatedPropertyBase : public RefCounted<SVGAnimatedPropertyBase> { 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 bool needsSynchronizeAttribute() = 0; 60 virtual void synchronizeAttribute(); 61 62 AnimatedPropertyType type() const 63 { 64 return m_type; 65 } 66 67 SVGElement* contextElement() const 68 { 69 return m_contextElement; 70 } 71 72 const QualifiedName& attributeName() const 73 { 74 return m_attributeName; 75 } 76 77 bool isReadOnly() const 78 { 79 return m_isReadOnly; 80 } 81 82 void setReadOnly() 83 { 84 m_isReadOnly = true; 85 } 86 87 bool isSpecified() const; 88 89 protected: 90 SVGAnimatedPropertyBase(AnimatedPropertyType, SVGElement*, const QualifiedName& attributeName); 91 92 private: 93 const AnimatedPropertyType m_type; 94 bool m_isReadOnly; 95 96 // This reference is kept alive from V8 wrapper 97 SVGElement* m_contextElement; 98 99 const QualifiedName& m_attributeName; 100 101 WTF_MAKE_NONCOPYABLE(SVGAnimatedPropertyBase); 102 }; 103 104 template <typename Property> 105 class SVGAnimatedPropertyCommon : public SVGAnimatedPropertyBase { 106 public: 107 Property* baseValue() 108 { 109 return m_baseValue.get(); 110 } 111 112 Property* currentValue() 113 { 114 return m_currentValue ? m_currentValue.get() : m_baseValue.get(); 115 } 116 117 const Property* currentValue() const 118 { 119 return const_cast<SVGAnimatedPropertyCommon*>(this)->currentValue(); 120 } 121 122 virtual SVGPropertyBase* currentValueBase() OVERRIDE 123 { 124 return currentValue(); 125 } 126 127 virtual bool isAnimating() const OVERRIDE 128 { 129 return m_currentValue; 130 } 131 132 void setBaseValueAsString(const String& value, SVGParsingError& parseError) 133 { 134 TrackExceptionState es; 135 136 m_baseValue->setValueAsString(value, es); 137 138 if (es.hadException()) 139 parseError = ParsingAttributeFailedError; 140 } 141 142 virtual PassRefPtr<SVGPropertyBase> createAnimatedValue() OVERRIDE 143 { 144 return m_baseValue->clone(); 145 } 146 147 virtual void setAnimatedValue(PassRefPtr<SVGPropertyBase> passValue) OVERRIDE 148 { 149 RefPtr<SVGPropertyBase> value = passValue; 150 ASSERT(value->type() == Property::classType()); 151 m_currentValue = static_pointer_cast<Property>(value.release()); 152 } 153 154 virtual void animationEnded() OVERRIDE 155 { 156 m_currentValue.clear(); 157 158 SVGAnimatedPropertyBase::animationEnded(); 159 } 160 161 protected: 162 SVGAnimatedPropertyCommon(SVGElement* contextElement, const QualifiedName& attributeName, PassRefPtr<Property> initialValue) 163 : SVGAnimatedPropertyBase(Property::classType(), contextElement, attributeName) 164 , m_baseValue(initialValue) 165 { 166 } 167 168 private: 169 RefPtr<Property> m_baseValue; 170 RefPtr<Property> m_currentValue; 171 }; 172 173 // Implementation of SVGAnimatedProperty which uses primitive types. 174 // This is for classes which return primitive type for its "animVal". 175 // Examples are SVGAnimatedBoolean, SVGAnimatedNumber, etc. 176 template <typename Property, typename TearOffType = typename Property::TearOffType, typename PrimitiveType = typename Property::PrimitiveType> 177 class SVGAnimatedProperty : public SVGAnimatedPropertyCommon<Property> { 178 public: 179 virtual bool needsSynchronizeAttribute() OVERRIDE 180 { 181 // DOM attribute synchronization is only needed if tear-off is being touched from javascript or the property is being animated. 182 // This prevents unnecessary attribute creation on target element. 183 return m_baseValueUpdated || this->isAnimating(); 184 } 185 186 virtual void synchronizeAttribute() OVERRIDE 187 { 188 SVGAnimatedPropertyBase::synchronizeAttribute(); 189 m_baseValueUpdated = false; 190 } 191 192 // SVGAnimated* DOM Spec implementations: 193 194 // baseVal()/setBaseVal()/animVal() are only to be used from SVG DOM implementation. 195 // Use currentValue() from C++ code. 196 PrimitiveType baseVal() 197 { 198 return this->baseValue()->value(); 199 } 200 201 void setBaseVal(PrimitiveType value, WebCore::ExceptionState& exceptionState) 202 { 203 if (this->isReadOnly()) { 204 exceptionState.throwDOMException(NoModificationAllowedError, "The attribute is read-only."); 205 return; 206 } 207 208 this->baseValue()->setValue(value); 209 m_baseValueUpdated = true; 210 211 ASSERT(this->attributeName() != QualifiedName::null()); 212 this->contextElement()->invalidateSVGAttributes(); 213 this->contextElement()->svgAttributeChanged(this->attributeName()); 214 } 215 216 PrimitiveType animVal() 217 { 218 return this->currentValue()->value(); 219 } 220 221 protected: 222 SVGAnimatedProperty(SVGElement* contextElement, const QualifiedName& attributeName, PassRefPtr<Property> initialValue) 223 : SVGAnimatedPropertyCommon<Property>(contextElement, attributeName, initialValue) 224 , m_baseValueUpdated(false) 225 { 226 } 227 228 bool m_baseValueUpdated; 229 }; 230 231 // Implementation of SVGAnimatedProperty which uses tear-off value types. 232 // These classes has "void" for its PrimitiveType. 233 // This is for classes which return special type for its "animVal". 234 // Examples are SVGAnimatedLength, SVGAnimatedRect, SVGAnimated*List, etc. 235 template <typename Property, typename TearOffType> 236 class SVGAnimatedProperty<Property, TearOffType, void> : public SVGAnimatedPropertyCommon<Property> { 237 public: 238 static PassRefPtr<SVGAnimatedProperty<Property> > create(SVGElement* contextElement, const QualifiedName& attributeName, PassRefPtr<Property> initialValue) 239 { 240 return adoptRef(new SVGAnimatedProperty<Property>(contextElement, attributeName, initialValue)); 241 } 242 243 virtual void setAnimatedValue(PassRefPtr<SVGPropertyBase> value) OVERRIDE 244 { 245 SVGAnimatedPropertyCommon<Property>::setAnimatedValue(value); 246 updateAnimValTearOffIfNeeded(); 247 } 248 249 virtual void animationEnded() OVERRIDE 250 { 251 SVGAnimatedPropertyCommon<Property>::animationEnded(); 252 updateAnimValTearOffIfNeeded(); 253 } 254 255 virtual bool needsSynchronizeAttribute() OVERRIDE 256 { 257 // DOM attribute synchronization is only needed if tear-off is being touched from javascript or the property is being animated. 258 // This prevents unnecessary attribute creation on target element. 259 return m_baseValTearOff || this->isAnimating(); 260 } 261 262 // SVGAnimated* DOM Spec implementations: 263 264 // baseVal()/animVal() are only to be used from SVG DOM implementation. 265 // Use currentValue() from C++ code. 266 virtual TearOffType* baseVal() 267 { 268 if (!m_baseValTearOff) { 269 m_baseValTearOff = TearOffType::create(this->baseValue(), this->contextElement(), PropertyIsNotAnimVal, this->attributeName()); 270 if (this->isReadOnly()) 271 m_baseValTearOff->setIsReadOnlyProperty(); 272 } 273 274 return m_baseValTearOff.get(); 275 } 276 277 TearOffType* animVal() 278 { 279 if (!m_animValTearOff) 280 m_animValTearOff = TearOffType::create(this->currentValue(), this->contextElement(), PropertyIsAnimVal, this->attributeName()); 281 282 return m_animValTearOff.get(); 283 } 284 285 protected: 286 SVGAnimatedProperty(SVGElement* contextElement, const QualifiedName& attributeName, PassRefPtr<Property> initialValue) 287 : SVGAnimatedPropertyCommon<Property>(contextElement, attributeName, initialValue) 288 { 289 } 290 291 private: 292 void updateAnimValTearOffIfNeeded() 293 { 294 if (m_animValTearOff) 295 m_animValTearOff->setTarget(this->currentValue()); 296 } 297 298 // When still (not animated): 299 // Both m_animValTearOff and m_baseValTearOff target m_baseValue. 300 // When animated: 301 // m_animValTearOff targets m_currentValue. 302 // m_baseValTearOff targets m_baseValue. 303 RefPtr<TearOffType> m_baseValTearOff; 304 RefPtr<TearOffType> m_animValTearOff; 305 }; 306 307 } 308 309 #endif // SVGAnimatedProperty_h 310