Clean up ContainerNode::childrenChanged
[WebKit-https.git] / Source / WebCore / svg / SVGMarkerElement.cpp
1 /*
2  * Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3  * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
4  * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #include "config.h"
23
24 #if ENABLE(SVG)
25 #include "SVGMarkerElement.h"
26
27 #include "Attribute.h"
28 #include "RenderSVGResourceMarker.h"
29 #include "SVGElementInstance.h"
30 #include "SVGFitToViewBox.h"
31 #include "SVGNames.h"
32 #include "SVGSVGElement.h"
33
34 namespace WebCore {
35  
36 // Define custom animated property 'orientType'.
37 const SVGPropertyInfo* SVGMarkerElement::orientTypePropertyInfo()
38 {
39     static const SVGPropertyInfo* s_propertyInfo = 0;
40     if (!s_propertyInfo) {
41         s_propertyInfo = new SVGPropertyInfo(AnimatedEnumeration,
42                                              PropertyIsReadWrite,
43                                              SVGNames::orientAttr,
44                                              orientTypeIdentifier(),
45                                              &SVGMarkerElement::synchronizeOrientType,
46                                              &SVGMarkerElement::lookupOrCreateOrientTypeWrapper);
47     }
48     return s_propertyInfo;
49 }
50
51 // Animated property definitions
52 DEFINE_ANIMATED_LENGTH(SVGMarkerElement, SVGNames::refXAttr, RefX, refX)
53 DEFINE_ANIMATED_LENGTH(SVGMarkerElement, SVGNames::refYAttr, RefY, refY)
54 DEFINE_ANIMATED_LENGTH(SVGMarkerElement, SVGNames::markerWidthAttr, MarkerWidth, markerWidth)
55 DEFINE_ANIMATED_LENGTH(SVGMarkerElement, SVGNames::markerHeightAttr, MarkerHeight, markerHeight)
56 DEFINE_ANIMATED_ENUMERATION(SVGMarkerElement, SVGNames::markerUnitsAttr, MarkerUnits, markerUnits, SVGMarkerUnitsType)
57 DEFINE_ANIMATED_ANGLE_AND_ENUMERATION(SVGMarkerElement, SVGNames::orientAttr, orientAngleIdentifier(), OrientAngle, orientAngle)
58 DEFINE_ANIMATED_BOOLEAN(SVGMarkerElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
59 DEFINE_ANIMATED_RECT(SVGMarkerElement, SVGNames::viewBoxAttr, ViewBox, viewBox)
60 DEFINE_ANIMATED_PRESERVEASPECTRATIO(SVGMarkerElement, SVGNames::preserveAspectRatioAttr, PreserveAspectRatio, preserveAspectRatio)
61
62 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGMarkerElement)
63     REGISTER_LOCAL_ANIMATED_PROPERTY(refX)
64     REGISTER_LOCAL_ANIMATED_PROPERTY(refY)
65     REGISTER_LOCAL_ANIMATED_PROPERTY(markerWidth)
66     REGISTER_LOCAL_ANIMATED_PROPERTY(markerHeight)
67     REGISTER_LOCAL_ANIMATED_PROPERTY(markerUnits)
68     REGISTER_LOCAL_ANIMATED_PROPERTY(orientAngle)
69     REGISTER_LOCAL_ANIMATED_PROPERTY(orientType)
70     REGISTER_LOCAL_ANIMATED_PROPERTY(externalResourcesRequired)
71     REGISTER_LOCAL_ANIMATED_PROPERTY(viewBox)
72     REGISTER_LOCAL_ANIMATED_PROPERTY(preserveAspectRatio)
73     REGISTER_PARENT_ANIMATED_PROPERTIES(SVGElement)
74 END_REGISTER_ANIMATED_PROPERTIES
75
76 inline SVGMarkerElement::SVGMarkerElement(const QualifiedName& tagName, Document* document)
77     : SVGElement(tagName, document)
78     , m_refX(LengthModeWidth)
79     , m_refY(LengthModeHeight)
80     , m_markerWidth(LengthModeWidth, "3")
81     , m_markerHeight(LengthModeHeight, "3") 
82     , m_markerUnits(SVGMarkerUnitsStrokeWidth)
83     , m_orientType(SVGMarkerOrientAngle)
84 {
85     // Spec: If the markerWidth/markerHeight attribute is not specified, the effect is as if a value of "3" were specified.
86     ASSERT(hasTagName(SVGNames::markerTag));
87     registerAnimatedPropertiesForSVGMarkerElement();
88 }
89
90 PassRefPtr<SVGMarkerElement> SVGMarkerElement::create(const QualifiedName& tagName, Document* document)
91 {
92     return adoptRef(new SVGMarkerElement(tagName, document));
93 }
94
95 const AtomicString& SVGMarkerElement::orientTypeIdentifier()
96 {
97     DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGOrientType", AtomicString::ConstructFromLiteral));
98     return s_identifier;
99 }
100
101 const AtomicString& SVGMarkerElement::orientAngleIdentifier()
102 {
103     DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGOrientAngle", AtomicString::ConstructFromLiteral));
104     return s_identifier;
105 }
106
107 AffineTransform SVGMarkerElement::viewBoxToViewTransform(float viewWidth, float viewHeight) const
108 {
109     return SVGFitToViewBox::viewBoxToViewTransform(viewBox(), preserveAspectRatio(), viewWidth, viewHeight);
110 }
111
112 bool SVGMarkerElement::isSupportedAttribute(const QualifiedName& attrName)
113 {
114     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
115     if (supportedAttributes.isEmpty()) {
116         SVGLangSpace::addSupportedAttributes(supportedAttributes);
117         SVGExternalResourcesRequired::addSupportedAttributes(supportedAttributes);
118         SVGFitToViewBox::addSupportedAttributes(supportedAttributes);
119         supportedAttributes.add(SVGNames::markerUnitsAttr);
120         supportedAttributes.add(SVGNames::refXAttr);
121         supportedAttributes.add(SVGNames::refYAttr);
122         supportedAttributes.add(SVGNames::markerWidthAttr);
123         supportedAttributes.add(SVGNames::markerHeightAttr);
124         supportedAttributes.add(SVGNames::orientAttr);
125     }
126     return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName);
127 }
128
129 void SVGMarkerElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
130 {
131     SVGParsingError parseError = NoError;
132
133     if (!isSupportedAttribute(name))
134         SVGElement::parseAttribute(name, value);
135     else if (name == SVGNames::markerUnitsAttr) {
136         SVGMarkerUnitsType propertyValue = SVGPropertyTraits<SVGMarkerUnitsType>::fromString(value);
137         if (propertyValue > 0)
138             setMarkerUnitsBaseValue(propertyValue);
139     } else if (name == SVGNames::refXAttr)
140         setRefXBaseValue(SVGLength::construct(LengthModeWidth, value, parseError));
141     else if (name == SVGNames::refYAttr)
142         setRefYBaseValue(SVGLength::construct(LengthModeHeight, value, parseError));
143     else if (name == SVGNames::markerWidthAttr)
144         setMarkerWidthBaseValue(SVGLength::construct(LengthModeWidth, value, parseError));
145     else if (name == SVGNames::markerHeightAttr)
146         setMarkerHeightBaseValue(SVGLength::construct(LengthModeHeight, value, parseError));
147     else if (name == SVGNames::orientAttr) {
148         SVGAngle angle;
149         SVGMarkerOrientType orientType = SVGPropertyTraits<SVGMarkerOrientType>::fromString(value, angle);
150         if (orientType > 0)
151             setOrientTypeBaseValue(orientType);
152         if (orientType == SVGMarkerOrientAngle)
153             setOrientAngleBaseValue(angle);
154     } else if (SVGLangSpace::parseAttribute(name, value)
155              || SVGExternalResourcesRequired::parseAttribute(name, value)
156              || SVGFitToViewBox::parseAttribute(this, name, value)) {
157     } else
158         ASSERT_NOT_REACHED();
159
160     reportAttributeParsingError(parseError, name, value);
161 }
162
163 void SVGMarkerElement::svgAttributeChanged(const QualifiedName& attrName)
164 {
165     if (!isSupportedAttribute(attrName)) {
166         SVGElement::svgAttributeChanged(attrName);
167         return;
168     }
169
170     SVGElementInstance::InvalidationGuard invalidationGuard(this);
171     
172     if (attrName == SVGNames::refXAttr
173         || attrName == SVGNames::refYAttr
174         || attrName == SVGNames::markerWidthAttr
175         || attrName == SVGNames::markerHeightAttr)
176         updateRelativeLengthsInformation();
177
178     if (RenderObject* object = renderer())
179         object->setNeedsLayout(true);
180 }
181
182 void SVGMarkerElement::childrenChanged(const ChildChange& change)
183 {
184     SVGElement::childrenChanged(change);
185
186     if (change.source == ChildChangeSourceParser)
187         return;
188
189     if (RenderObject* object = renderer())
190         object->setNeedsLayout(true);
191 }
192
193 void SVGMarkerElement::setOrientToAuto()
194 {
195     setOrientTypeBaseValue(SVGMarkerOrientAuto);
196     setOrientAngleBaseValue(SVGAngle());
197  
198     // Mark orientAttr dirty - the next XML DOM access of that attribute kicks in synchronization.
199     m_orientAngle.shouldSynchronize = true;
200     m_orientType.shouldSynchronize = true;
201     invalidateSVGAttributes();
202     svgAttributeChanged(orientAnglePropertyInfo()->attributeName);
203 }
204
205 void SVGMarkerElement::setOrientToAngle(const SVGAngle& angle)
206 {
207     setOrientTypeBaseValue(SVGMarkerOrientAngle);
208     setOrientAngleBaseValue(angle);
209
210     // Mark orientAttr dirty - the next XML DOM access of that attribute kicks in synchronization.
211     m_orientAngle.shouldSynchronize = true;
212     m_orientType.shouldSynchronize = true;
213     invalidateSVGAttributes();
214     svgAttributeChanged(orientAnglePropertyInfo()->attributeName);
215 }
216
217 RenderObject* SVGMarkerElement::createRenderer(RenderArena* arena, RenderStyle*)
218 {
219     return new (arena) RenderSVGResourceMarker(this);
220 }
221
222 bool SVGMarkerElement::selfHasRelativeLengths() const
223 {
224     return refX().isRelative()
225         || refY().isRelative()
226         || markerWidth().isRelative()
227         || markerHeight().isRelative();
228 }
229
230 void SVGMarkerElement::synchronizeOrientType(SVGElement* contextElement)
231 {
232     ASSERT(contextElement);
233     SVGMarkerElement* ownerType = toSVGMarkerElement(contextElement);
234     if (!ownerType->m_orientType.shouldSynchronize)
235         return;
236
237     // If orient is not auto, the previous call to synchronizeOrientAngle already set the orientAttr to the right angle.
238     if (ownerType->m_orientType.value != SVGMarkerOrientAuto)
239         return;
240
241     DEFINE_STATIC_LOCAL(AtomicString, autoString, ("auto", AtomicString::ConstructFromLiteral));
242     ownerType->m_orientType.synchronize(ownerType, orientTypePropertyInfo()->attributeName, autoString);
243 }
244
245 PassRefPtr<SVGAnimatedProperty> SVGMarkerElement::lookupOrCreateOrientTypeWrapper(SVGElement* contextElement)
246 {
247     ASSERT(contextElement);
248     SVGMarkerElement* ownerType = toSVGMarkerElement(contextElement);
249     return SVGAnimatedProperty::lookupOrCreateWrapper<SVGMarkerElement, SVGAnimatedEnumerationPropertyTearOff<SVGMarkerOrientType>, SVGMarkerOrientType>
250            (ownerType, orientTypePropertyInfo(), ownerType->m_orientType.value);
251 }
252   
253 PassRefPtr<SVGAnimatedEnumerationPropertyTearOff<SVGMarkerOrientType> > SVGMarkerElement::orientTypeAnimated()
254 {
255     m_orientType.shouldSynchronize = true;
256     return static_pointer_cast<SVGAnimatedEnumerationPropertyTearOff<SVGMarkerOrientType> >(lookupOrCreateOrientTypeWrapper(this));
257 }
258
259 }
260
261 #endif