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 "SVGAnimatedProperty.h" 24#include "SVGElement.h" 25#include "SVGProperty.h" 26#include <wtf/WeakPtr.h> 27 28namespace WebCore { 29 30class SVGPropertyTearOffBase : public SVGProperty { 31public: 32 virtual void detachWrapper() = 0; 33}; 34 35template<typename PropertyType> 36class SVGPropertyTearOff : public SVGPropertyTearOffBase { 37public: 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() override 107 { 108 if (!m_animatedProperty || m_valueIsCopy) 109 return; 110 m_animatedProperty->commitChange(); 111 } 112 113 virtual bool isReadOnly() const override 114 { 115 if (m_role == AnimValRole) 116 return true; 117 if (m_animatedProperty && m_animatedProperty->isReadOnly()) 118 return true; 119 return false; 120 } 121 122protected: 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 detachChildren(); 148 delete m_value; 149 } 150 } 151 152 void detachChildren() 153 { 154 for (const auto& childTearOff : m_childTearOffs) { 155 if (childTearOff.get()) 156 childTearOff.get()->detachWrapper(); 157 } 158 m_childTearOffs.clear(); 159 } 160 161 RefPtr<SVGElement> m_contextElement; 162 SVGAnimatedProperty* m_animatedProperty; 163 SVGPropertyRole m_role; 164 PropertyType* m_value; 165 Vector<WeakPtr<SVGPropertyTearOffBase>> m_childTearOffs; 166 bool m_valueIsCopy : 1; 167}; 168 169} 170 171#endif // SVGPropertyTearOff_h 172