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