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/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 
     63     AnimatedPropertyType type() const
     64     {
     65         return m_type;
     66     }
     67 
     68     SVGElement* contextElement() const
     69     {
     70         return m_contextElement;
     71     }
     72 
     73     const QualifiedName& attributeName() const
     74     {
     75         return m_attributeName;
     76     }
     77 
     78     bool isReadOnly() const
     79     {
     80         return m_isReadOnly;
     81     }
     82 
     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:
    108     Property* baseValue()
    109     {
    110         return m_baseValue.get();
    111     }
    112 
    113     Property* currentValue()
    114     {
    115         return m_currentValue ? m_currentValue.get() : m_baseValue.get();
    116     }
    117 
    118     const Property* currentValue() const
    119     {
    120         return const_cast<SVGAnimatedPropertyCommon*>(this)->currentValue();
    121     }
    122 
    123     virtual SVGPropertyBase* currentValueBase() OVERRIDE
    124     {
    125         return currentValue();
    126     }
    127 
    128     virtual bool isAnimating() const OVERRIDE
    129     {
    130         return m_currentValue;
    131     }
    132 
    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 
    143     virtual PassRefPtr<SVGPropertyBase> createAnimatedValue() OVERRIDE
    144     {
    145         return m_baseValue->clone();
    146     }
    147 
    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 
    155     virtual void animationEnded() OVERRIDE
    156     {
    157         m_currentValue.clear();
    158 
    159         SVGAnimatedPropertyBase::animationEnded();
    160     }
    161 
    162 protected:
    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:
    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 
    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.
    197     PrimitiveType baseVal()
    198     {
    199         return this->baseValue()->value();
    200     }
    201 
    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 
    217     PrimitiveType animVal()
    218     {
    219         return this->currentValue()->value();
    220     }
    221 
    222 protected:
    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:
    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 
    244     virtual void setAnimatedValue(PassRefPtr<SVGPropertyBase> value) OVERRIDE
    245     {
    246         SVGAnimatedPropertyCommon<Property>::setAnimatedValue(value);
    247         updateAnimValTearOffIfNeeded();
    248     }
    249 
    250     virtual void animationEnded() OVERRIDE
    251     {
    252         SVGAnimatedPropertyCommon<Property>::animationEnded();
    253         updateAnimValTearOffIfNeeded();
    254     }
    255 
    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.
    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 
    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:
    287     SVGAnimatedProperty(SVGElement* contextElement, const QualifiedName& attributeName, PassRefPtr<Property> initialValue)
    288         : SVGAnimatedPropertyCommon<Property>(contextElement, attributeName, initialValue)
    289     {
    290     }
    291 
    292 private:
    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