Home | History | Annotate | Download | only in properties
      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