Home | History | Annotate | Download | only in properties
      1 /*
      2  * Copyright (C) Research In Motion Limited 2010. All rights reserved.
      3  *
      4  * This library is free software; you can redistribute it and/or
      5  * modify it under the terms of the GNU Library General Public
      6  * License as published by the Free Software Foundation; either
      7  * version 2 of the License, or (at your option) any later version.
      8  *
      9  * This library is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  * Library General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU Library General Public License
     15  * along with this library; see the file COPYING.LIB.  If not, write to
     16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     17  * Boston, MA 02110-1301, USA.
     18  */
     19 
     20 #ifndef SVGAnimatedListPropertyTearOff_h
     21 #define SVGAnimatedListPropertyTearOff_h
     22 
     23 #include "core/svg/properties/SVGAnimatedProperty.h"
     24 #include "core/svg/properties/SVGListPropertyTearOff.h"
     25 #include "core/svg/properties/SVGStaticListPropertyTearOff.h"
     26 
     27 namespace WebCore {
     28 
     29 template<typename PropertyType>
     30 class SVGPropertyTearOff;
     31 
     32 template<typename PropertyType>
     33 class SVGAnimatedListPropertyTearOff : public SVGAnimatedProperty {
     34 public:
     35     typedef typename SVGPropertyTraits<PropertyType>::ListItemType ListItemType;
     36     typedef SVGPropertyTearOff<ListItemType> ListItemTearOff;
     37     typedef Vector<RefPtr<ListItemTearOff> > ListWrapperCache;
     38     typedef SVGListProperty<PropertyType> ListProperty;
     39     typedef SVGListPropertyTearOff<PropertyType> ListPropertyTearOff;
     40     typedef PropertyType ContentType;
     41 
     42     virtual ListProperty* baseVal()
     43     {
     44         if (!m_baseVal)
     45             m_baseVal = ListPropertyTearOff::create(this, BaseValRole, m_values, m_wrappers);
     46         return static_cast<ListProperty*>(m_baseVal.get());
     47     }
     48 
     49     virtual ListProperty* animVal()
     50     {
     51         if (!m_animVal)
     52             m_animVal = ListPropertyTearOff::create(this, AnimValRole, m_values, m_wrappers);
     53         return static_cast<ListProperty*>(m_animVal.get());
     54     }
     55 
     56     virtual bool isAnimatedListTearOff() const { return true; }
     57 
     58     int findItem(SVGProperty* property) const
     59     {
     60         // This should ever be called for our baseVal, as animVal can't modify the list.
     61         // It's safe to cast to ListPropertyTearOff here as all classes inheriting from us supply their own removeItemFromList() method.
     62         typedef SVGPropertyTearOff<typename SVGPropertyTraits<PropertyType>::ListItemType> ListItemTearOff;
     63         return static_cast<ListPropertyTearOff*>(m_baseVal.get())->findItem(static_cast<ListItemTearOff*>(property));
     64     }
     65 
     66     void removeItemFromList(size_t itemIndex, bool shouldSynchronizeWrappers)
     67     {
     68         // This should ever be called for our baseVal, as animVal can't modify the list.
     69         // It's safe to cast to ListPropertyTearOff here as all classes inheriting from us supply their own removeItemFromList() method.
     70         static_cast<ListPropertyTearOff*>(m_baseVal.get())->removeItemFromList(itemIndex, shouldSynchronizeWrappers);
     71     }
     72 
     73     void detachListWrappers(unsigned newListSize)
     74     {
     75         ListProperty::detachListWrappersAndResize(&m_wrappers, newListSize);
     76     }
     77 
     78     PropertyType& currentAnimatedValue()
     79     {
     80         ASSERT(m_isAnimating);
     81         ASSERT(m_animVal);
     82         return static_cast<ListProperty*>(m_animVal.get())->values();
     83     }
     84 
     85     const PropertyType& currentBaseValue() const
     86     {
     87         return m_values;
     88     }
     89 
     90     void animationStarted(PropertyType* newAnimVal, bool shouldOwnValues = false)
     91     {
     92         ASSERT(!m_isAnimating);
     93         ASSERT(newAnimVal);
     94         ASSERT(m_values.size() == m_wrappers.size());
     95         ASSERT(m_animatedWrappers.isEmpty());
     96 
     97         // Switch to new passed in value type & new wrappers list. The new wrappers list must be created for the new value.
     98         if (!newAnimVal->isEmpty())
     99             m_animatedWrappers.fill(0, newAnimVal->size());
    100 
    101         ListProperty* animVal = static_cast<ListProperty*>(this->animVal());
    102         animVal->setValuesAndWrappers(newAnimVal, &m_animatedWrappers, shouldOwnValues);
    103         ASSERT(animVal->values().size() == animVal->wrappers().size());
    104         ASSERT(animVal->wrappers().size() == m_animatedWrappers.size());
    105         m_isAnimating = true;
    106     }
    107 
    108     void animationEnded()
    109     {
    110         ASSERT(m_isAnimating);
    111         ASSERT(m_animVal);
    112         ASSERT(m_values.size() == m_wrappers.size());
    113 
    114         ListProperty* animVal = static_cast<ListProperty*>(m_animVal.get());
    115         ASSERT(animVal->values().size() == animVal->wrappers().size());
    116         ASSERT(animVal->wrappers().size() == m_animatedWrappers.size());
    117 
    118         animVal->setValuesAndWrappers(&m_values, &m_wrappers, false);
    119         ASSERT(animVal->values().size() == animVal->wrappers().size());
    120         ASSERT(animVal->wrappers().size() == m_wrappers.size());
    121 
    122         m_animatedWrappers.clear();
    123         m_isAnimating = false;
    124     }
    125 
    126     void synchronizeWrappersIfNeeded()
    127     {
    128         // Eventually the wrapper list needs synchronization because any SVGAnimateLengthList::calculateAnimatedValue() call may
    129         // mutate the length of our values() list, and thus the wrapper() cache needs synchronization, to have the same size.
    130         // Also existing wrappers which point directly at elements in the existing SVGLengthList have to be detached (so a copy
    131         // of them is created, so existing animVal variables in JS are kept-alive). If we'd detach them later the underlying
    132         // SVGLengthList was already mutated, and our list item wrapper tear offs would point nowhere. Assertions would fire.
    133         ListProperty* animVal = static_cast<ListProperty*>(m_animVal.get());
    134         animVal->detachListWrappers(animVal->values().size());
    135 
    136         ASSERT(animVal->values().size() == animVal->wrappers().size());
    137         ASSERT(animVal->wrappers().size() == m_animatedWrappers.size());
    138     }
    139 
    140     void animValWillChange()
    141     {
    142         ASSERT(m_isAnimating);
    143         ASSERT(m_animVal);
    144         ASSERT(m_values.size() == m_wrappers.size());
    145         synchronizeWrappersIfNeeded();
    146     }
    147 
    148     void animValDidChange()
    149     {
    150         ASSERT(m_isAnimating);
    151         ASSERT(m_animVal);
    152         ASSERT(m_values.size() == m_wrappers.size());
    153         synchronizeWrappersIfNeeded();
    154     }
    155 
    156     static PassRefPtr<SVGAnimatedListPropertyTearOff<PropertyType> > create(SVGElement* contextElement, const QualifiedName& attributeName, AnimatedPropertyType animatedPropertyType, PropertyType& values)
    157     {
    158         ASSERT(contextElement);
    159         return adoptRef(new SVGAnimatedListPropertyTearOff<PropertyType>(contextElement, attributeName, animatedPropertyType, values));
    160     }
    161 
    162 protected:
    163     SVGAnimatedListPropertyTearOff(SVGElement* contextElement, const QualifiedName& attributeName, AnimatedPropertyType animatedPropertyType, PropertyType& values)
    164         : SVGAnimatedProperty(contextElement, attributeName, animatedPropertyType)
    165         , m_values(values)
    166     {
    167         if (!values.isEmpty())
    168             m_wrappers.fill(0, values.size());
    169     }
    170 
    171     PropertyType& m_values;
    172 
    173     ListWrapperCache m_wrappers;
    174     ListWrapperCache m_animatedWrappers;
    175 
    176     RefPtr<SVGProperty> m_baseVal;
    177     RefPtr<SVGProperty> m_animVal;
    178 };
    179 
    180 }
    181 
    182 #endif // SVGAnimatedListPropertyTearOff_h
    183