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 SVGListPropertyTearOff_h
     21 #define SVGListPropertyTearOff_h
     22 
     23 #include "core/svg/properties/SVGListProperty.h"
     24 
     25 namespace WebCore {
     26 
     27 class ExceptionState;
     28 
     29 template<typename PropertyType>
     30 class SVGListPropertyTearOff : public SVGListProperty<PropertyType> {
     31 public:
     32     typedef SVGListProperty<PropertyType> Base;
     33     typedef SVGListPropertyTearOff<PropertyType> Self;
     34 
     35     typedef typename SVGPropertyTraits<PropertyType>::ListItemType ListItemType;
     36     typedef SVGPropertyTearOff<ListItemType> ListItemTearOff;
     37     typedef PassRefPtr<ListItemTearOff> PassListItemTearOff;
     38     typedef SVGAnimatedListPropertyTearOff<PropertyType> AnimatedListPropertyTearOff;
     39     typedef typename SVGAnimatedListPropertyTearOff<PropertyType>::ListWrapperCache ListWrapperCache;
     40 
     41     using Base::m_role;
     42     using Base::m_values;
     43     using Base::m_wrappers;
     44 
     45     static PassRefPtr<Self> create(AnimatedListPropertyTearOff* animatedProperty, SVGPropertyRole role, PropertyType& values, ListWrapperCache& wrappers)
     46     {
     47         ASSERT(animatedProperty);
     48         return adoptRef(new Self(animatedProperty, role, values, wrappers));
     49     }
     50 
     51     int findItem(ListItemTearOff* item) const
     52     {
     53         ASSERT(m_values);
     54         ASSERT(m_wrappers);
     55 
     56         unsigned size = m_wrappers->size();
     57         ASSERT(size == m_values->size());
     58         for (size_t i = 0; i < size; ++i) {
     59             if (item == m_wrappers->at(i))
     60                 return i;
     61         }
     62 
     63         return -1;
     64     }
     65 
     66     void removeItemFromList(size_t itemIndex, bool shouldSynchronizeWrappers)
     67     {
     68         ASSERT(m_values);
     69         ASSERT(m_wrappers);
     70         ASSERT(m_values->size() == m_wrappers->size());
     71         ASSERT_WITH_SECURITY_IMPLICATION(itemIndex < m_wrappers->size());
     72 
     73         RefPtr<ListItemTearOff>& item = m_wrappers->at(itemIndex);
     74         item->detachWrapper();
     75         m_wrappers->remove(itemIndex);
     76         m_values->remove(itemIndex);
     77 
     78         if (shouldSynchronizeWrappers)
     79             commitChange();
     80     }
     81 
     82     // SVGList API
     83     void clear(ExceptionState& exceptionState)
     84     {
     85         Base::clearValuesAndWrappers(exceptionState);
     86     }
     87 
     88     PassListItemTearOff initialize(PassListItemTearOff passNewItem, ExceptionState& exceptionState)
     89     {
     90         return Base::initializeValuesAndWrappers(passNewItem, exceptionState);
     91     }
     92 
     93     PassListItemTearOff getItem(unsigned index, ExceptionState& exceptionState)
     94     {
     95         ASSERT(m_animatedProperty);
     96         return Base::getItemValuesAndWrappers(m_animatedProperty, index, exceptionState);
     97     }
     98 
     99     PassListItemTearOff insertItemBefore(PassListItemTearOff passNewItem, unsigned index, ExceptionState& exceptionState)
    100     {
    101         return Base::insertItemBeforeValuesAndWrappers(passNewItem, index, exceptionState);
    102     }
    103 
    104     PassListItemTearOff replaceItem(PassListItemTearOff passNewItem, unsigned index, ExceptionState& exceptionState)
    105     {
    106         return Base::replaceItemValuesAndWrappers(passNewItem, index, exceptionState);
    107     }
    108 
    109     PassListItemTearOff removeItem(unsigned index, ExceptionState& exceptionState)
    110     {
    111         ASSERT(m_animatedProperty);
    112         return Base::removeItemValuesAndWrappers(m_animatedProperty, index, exceptionState);
    113     }
    114 
    115     PassListItemTearOff appendItem(PassListItemTearOff passNewItem, ExceptionState& exceptionState)
    116     {
    117         return Base::appendItemValuesAndWrappers(passNewItem, exceptionState);
    118     }
    119 
    120     SVGElement* contextElement() const
    121     {
    122         ASSERT(m_animatedProperty);
    123         return m_animatedProperty->contextElement();
    124     }
    125 
    126     void clearAnimatedProperty()
    127     {
    128         ASSERT(m_animatedProperty);
    129         m_animatedProperty = 0;
    130     }
    131 
    132 protected:
    133     SVGListPropertyTearOff(AnimatedListPropertyTearOff* animatedProperty, SVGPropertyRole role, PropertyType& values, ListWrapperCache& wrappers)
    134         : SVGListProperty<PropertyType>(role, values, &wrappers)
    135         , m_animatedProperty(animatedProperty)
    136     {
    137         ASSERT(m_animatedProperty);
    138     }
    139 
    140     virtual bool isReadOnly() const
    141     {
    142         if (m_role == AnimValRole)
    143             return true;
    144         if (m_animatedProperty && m_animatedProperty->isReadOnly())
    145             return true;
    146         return false;
    147     }
    148 
    149     virtual void commitChange()
    150     {
    151         ASSERT(m_values);
    152         ASSERT(m_wrappers);
    153         ASSERT(m_animatedProperty);
    154 
    155         // Update existing wrappers, as the index in the values list has changed.
    156         unsigned size = m_wrappers->size();
    157         ASSERT(size == m_values->size());
    158         for (unsigned i = 0; i < size; ++i) {
    159             ListItemTearOff* item = m_wrappers->at(i).get();
    160             if (!item)
    161                 continue;
    162             item->setAnimatedProperty(m_animatedProperty);
    163             item->setValue(m_values->at(i));
    164         }
    165 
    166         m_animatedProperty->commitChange();
    167     }
    168 
    169     virtual bool processIncomingListItemValue(const ListItemType&, unsigned*)
    170     {
    171         ASSERT_NOT_REACHED();
    172         return true;
    173     }
    174 
    175     virtual bool processIncomingListItemWrapper(RefPtr<ListItemTearOff>& newItem, unsigned* indexToModify)
    176     {
    177         SVGAnimatedProperty* animatedPropertyOfItem = newItem->animatedProperty();
    178 
    179         // newItem has been created manually, it doesn't belong to any SVGElement.
    180         // (for example: "textElement.x.baseVal.appendItem(svgsvgElement.createSVGLength())")
    181         if (!animatedPropertyOfItem)
    182             return true;
    183 
    184         // newItem belongs to a SVGElement, but its associated SVGAnimatedProperty is not an animated list tear off.
    185         // (for example: "textElement.x.baseVal.appendItem(rectElement.width.baseVal)")
    186         if (!animatedPropertyOfItem->isAnimatedListTearOff()) {
    187             // We have to copy the incoming newItem, as we're not allowed to insert this tear off as is into our wrapper cache.
    188             // Otherwhise we'll end up having two SVGAnimatedPropertys that operate on the same SVGPropertyTearOff. Consider the example above:
    189             // SVGRectElements SVGAnimatedLength 'width' property baseVal points to the same tear off object
    190             // that's inserted into SVGTextElements SVGAnimatedLengthList 'x'. textElement.x.baseVal.getItem(0).value += 150 would
    191             // mutate the rectElement width _and_ the textElement x list. That's obviously wrong, take care of that.
    192             newItem = ListItemTearOff::create(newItem->propertyReference());
    193             return true;
    194         }
    195 
    196         // Spec: If newItem is already in a list, it is removed from its previous list before it is inserted into this list.
    197         // 'newItem' is already living in another list. If it's not our list, synchronize the other lists wrappers after the removal.
    198         ASSERT(m_animatedProperty);
    199         bool livesInOtherList = animatedPropertyOfItem != m_animatedProperty;
    200         AnimatedListPropertyTearOff* propertyTearOff = static_cast<AnimatedListPropertyTearOff*>(animatedPropertyOfItem);
    201         int indexToRemove = propertyTearOff->findItem(newItem.get());
    202         ASSERT(indexToRemove != -1);
    203 
    204         // Do not remove newItem if already in this list at the target index.
    205         if (!livesInOtherList && indexToModify && static_cast<unsigned>(indexToRemove) == *indexToModify)
    206             return false;
    207 
    208         propertyTearOff->removeItemFromList(indexToRemove, livesInOtherList);
    209 
    210         if (!indexToModify)
    211             return true;
    212 
    213         // If the item lived in our list, adjust the insertion index.
    214         if (!livesInOtherList) {
    215             unsigned& index = *indexToModify;
    216             // Spec: If the item is already in this list, note that the index of the item to (replace|insert before) is before the removal of the item.
    217             if (static_cast<unsigned>(indexToRemove) < index)
    218                 --index;
    219         }
    220 
    221         return true;
    222     }
    223 
    224     // Back pointer to the animated property that created us
    225     // For example (text.x.baseVal): m_animatedProperty points to the 'x' SVGAnimatedLengthList object
    226     AnimatedListPropertyTearOff* m_animatedProperty;
    227 };
    228 
    229 }
    230 
    231 #endif // SVGListPropertyTearOff_h
    232