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 SVGPropertyTearOff_h
     21 #define SVGPropertyTearOff_h
     22 
     23 #include "core/svg/SVGElement.h"
     24 #include "core/svg/properties/SVGAnimatedProperty.h"
     25 #include "core/svg/properties/SVGProperty.h"
     26 #include "wtf/WeakPtr.h"
     27 
     28 namespace WebCore {
     29 
     30 class SVGPropertyTearOffBase : public SVGProperty {
     31 public:
     32     virtual void setValueForMatrixIfNeeded(SVGTransform*) { }
     33 
     34     virtual void detachWrapper() = 0;
     35 };
     36 
     37 template<typename PropertyType>
     38 class SVGPropertyTearOff : public SVGPropertyTearOffBase {
     39 public:
     40     typedef SVGPropertyTearOff<PropertyType> Self;
     41 
     42     // Used for child types (baseVal/animVal) of a SVGAnimated* property (for example: SVGAnimatedLength::baseVal()).
     43     // Also used for list tear offs (for example: text.x.baseVal.getItem(0)).
     44     static PassRefPtr<Self> create(SVGAnimatedProperty* animatedProperty, SVGPropertyRole role, PropertyType& value)
     45     {
     46         ASSERT(animatedProperty);
     47         return adoptRef(new Self(animatedProperty, role, value));
     48     }
     49 
     50     // Used for non-animated POD types (for example: SVGSVGElement::createSVGLength()).
     51     static PassRefPtr<Self> create(const PropertyType& initialValue)
     52     {
     53         return adoptRef(new Self(initialValue));
     54     }
     55 
     56     PropertyType& propertyReference() { return *m_value; }
     57     SVGAnimatedProperty* animatedProperty() const { return m_animatedProperty; }
     58 
     59     void setValue(PropertyType& value)
     60     {
     61         if (m_valueIsCopy) {
     62             detachChildren();
     63             delete m_value;
     64         }
     65 
     66         updateChildrenTearOffs(&value);
     67 
     68         m_valueIsCopy = false;
     69         m_value = &value;
     70     }
     71 
     72     void setAnimatedProperty(SVGAnimatedProperty* animatedProperty)
     73     {
     74         m_animatedProperty = animatedProperty;
     75 
     76         if (m_animatedProperty)
     77             m_contextElement = m_animatedProperty->contextElement();
     78     }
     79 
     80     SVGElement* contextElement() const
     81     {
     82         if (!m_animatedProperty || m_valueIsCopy)
     83             return 0;
     84         ASSERT(m_contextElement);
     85         return m_contextElement;
     86     }
     87 
     88     void addChild(WeakPtr<SVGPropertyTearOffBase> child)
     89     {
     90         m_childTearOffs.append(child);
     91     }
     92 
     93     virtual void detachWrapper() OVERRIDE
     94     {
     95         if (m_valueIsCopy)
     96             return;
     97 
     98         detachChildren();
     99 
    100         // Switch from a live value, to a non-live value.
    101         // For example: <text x="50"/>
    102         // var item = text.x.baseVal.getItem(0);
    103         // text.setAttribute("x", "100");
    104         // item.value still has to report '50' and it has to be possible to modify 'item'
    105         // w/o changing the "new item" (with x=100) in the text element.
    106         // Whenever the XML DOM modifies the "x" attribute, all existing wrappers are detached, using this function.
    107         m_value = new PropertyType(*m_value);
    108         m_valueIsCopy = true;
    109         m_animatedProperty = 0;
    110     }
    111 
    112     virtual void commitChange()
    113     {
    114         if (!m_animatedProperty || m_valueIsCopy)
    115             return;
    116         m_animatedProperty->commitChange();
    117     }
    118 
    119     virtual bool isReadOnly() const
    120     {
    121         if (m_role == AnimValRole)
    122             return true;
    123         if (m_animatedProperty && m_animatedProperty->isReadOnly())
    124             return true;
    125         return false;
    126     }
    127 
    128 protected:
    129     SVGPropertyTearOff(SVGAnimatedProperty* animatedProperty, SVGPropertyRole role, PropertyType& value)
    130         : m_animatedProperty(animatedProperty)
    131         , m_role(role)
    132         , m_value(&value)
    133         , m_valueIsCopy(false)
    134     {
    135         // Using operator & is completely fine, as SVGAnimatedProperty owns this reference,
    136         // and we're guaranteed to live as long as SVGAnimatedProperty does.
    137 
    138         if (m_animatedProperty)
    139             m_contextElement = m_animatedProperty->contextElement();
    140     }
    141 
    142     SVGPropertyTearOff(const PropertyType& initialValue)
    143         : m_animatedProperty(0)
    144         , m_role(UndefinedRole)
    145         , m_value(new PropertyType(initialValue))
    146         , m_valueIsCopy(true)
    147     {
    148     }
    149 
    150     virtual ~SVGPropertyTearOff()
    151     {
    152         if (m_valueIsCopy)
    153             delete m_value;
    154     }
    155 
    156     void detachChildren()
    157     {
    158         for (Vector<WeakPtr<SVGPropertyTearOffBase> >::iterator iter = m_childTearOffs.begin(); iter != m_childTearOffs.end(); iter++) {
    159             if (iter->get())
    160                 iter->get()->detachWrapper();
    161         }
    162         m_childTearOffs.clear();
    163     }
    164 
    165     // Update m_value of children tear-offs.
    166     // Currently only SVGTransform has child tear-offs.
    167     void updateChildrenTearOffs(SVGTransform* transform)
    168     {
    169         for (Vector<WeakPtr<SVGPropertyTearOffBase> >::iterator iter = m_childTearOffs.begin(); iter != m_childTearOffs.end(); iter++) {
    170             if (iter->get())
    171                 iter->get()->setValueForMatrixIfNeeded(transform);
    172         }
    173     }
    174 
    175     void updateChildrenTearOffs(void*)
    176     {
    177         // Tear-offs for other types do not have child tear-offs.
    178     }
    179 
    180     SVGElement* m_contextElement;
    181     SVGAnimatedProperty* m_animatedProperty;
    182     SVGPropertyRole m_role;
    183     PropertyType* m_value;
    184     Vector<WeakPtr<SVGPropertyTearOffBase> > m_childTearOffs;
    185     bool m_valueIsCopy : 1;
    186 };
    187 
    188 }
    189 
    190 #endif // SVGPropertyTearOff_h
    191