Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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 #include "core/svg/SVGMarkerElement.h"
25
26 #include "SVGNames.h"
27 #include "core/rendering/svg/RenderSVGResourceMarker.h"
28 #include "core/svg/SVGElementInstance.h"
29
30 namespace WebCore {
31
32 // Define custom animated property 'orientType'.
33 const SVGPropertyInfo* SVGMarkerElement::orientTypePropertyInfo()
34 {
35     static const SVGPropertyInfo* s_propertyInfo = 0;
36     if (!s_propertyInfo) {
37         s_propertyInfo = new SVGPropertyInfo(AnimatedEnumeration,
38                                              PropertyIsReadWrite,
39                                              SVGNames::orientAttr,
40                                              orientTypeIdentifier(),
41                                              &SVGMarkerElement::synchronizeOrientType,
42                                              &SVGMarkerElement::lookupOrCreateOrientTypeWrapper);
43     }
44     return s_propertyInfo;
45 }
46
47 // Animated property definitions
48 DEFINE_ANIMATED_ENUMERATION(SVGMarkerElement, SVGNames::markerUnitsAttr, MarkerUnits, markerUnits, SVGMarkerUnitsType)
49 DEFINE_ANIMATED_ANGLE_AND_ENUMERATION(SVGMarkerElement, SVGNames::orientAttr, orientAngleIdentifier(), OrientAngle, orientAngle)
50
51 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGMarkerElement)
52     REGISTER_LOCAL_ANIMATED_PROPERTY(markerUnits)
53     REGISTER_LOCAL_ANIMATED_PROPERTY(orientAngle)
54     REGISTER_LOCAL_ANIMATED_PROPERTY(orientType)
55     REGISTER_PARENT_ANIMATED_PROPERTIES(SVGElement)
56 END_REGISTER_ANIMATED_PROPERTIES
57
58 inline SVGMarkerElement::SVGMarkerElement(Document& document)
59     : SVGElement(SVGNames::markerTag, document)
60     , SVGFitToViewBox(this)
61     , m_refX(SVGAnimatedLength::create(this, SVGNames::refXAttr, SVGLength::create(LengthModeWidth)))
62     , m_refY(SVGAnimatedLength::create(this, SVGNames::refXAttr, SVGLength::create(LengthModeWidth)))
63     , m_markerWidth(SVGAnimatedLength::create(this, SVGNames::markerWidthAttr, SVGLength::create(LengthModeWidth)))
64     , m_markerHeight(SVGAnimatedLength::create(this, SVGNames::markerHeightAttr, SVGLength::create(LengthModeHeight)))
65     , m_orientType(SVGMarkerOrientAngle)
66     , m_markerUnits(SVGMarkerUnitsStrokeWidth)
67 {
68     ScriptWrappable::init(this);
69
70     // Spec: If the markerWidth/markerHeight attribute is not specified, the effect is as if a value of "3" were specified.
71     m_markerWidth->setDefaultValueAsString("3");
72     m_markerHeight->setDefaultValueAsString("3");
73
74     addToPropertyMap(m_refX);
75     addToPropertyMap(m_refY);
76     addToPropertyMap(m_markerWidth);
77     addToPropertyMap(m_markerHeight);
78
79     registerAnimatedPropertiesForSVGMarkerElement();
80 }
81
82 PassRefPtr<SVGMarkerElement> SVGMarkerElement::create(Document& document)
83 {
84     return adoptRef(new SVGMarkerElement(document));
85 }
86
87 const AtomicString& SVGMarkerElement::orientTypeIdentifier()
88 {
89     DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGOrientType", AtomicString::ConstructFromLiteral));
90     return s_identifier;
91 }
92
93 const AtomicString& SVGMarkerElement::orientAngleIdentifier()
94 {
95     DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGOrientAngle", AtomicString::ConstructFromLiteral));
96     return s_identifier;
97 }
98
99 AffineTransform SVGMarkerElement::viewBoxToViewTransform(float viewWidth, float viewHeight) const
100 {
101     return SVGFitToViewBox::viewBoxToViewTransform(viewBox()->currentValue()->value(), preserveAspectRatio()->currentValue(), viewWidth, viewHeight);
102 }
103
104 bool SVGMarkerElement::isSupportedAttribute(const QualifiedName& attrName)
105 {
106     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
107     if (supportedAttributes.isEmpty()) {
108         SVGFitToViewBox::addSupportedAttributes(supportedAttributes);
109         supportedAttributes.add(SVGNames::markerUnitsAttr);
110         supportedAttributes.add(SVGNames::refXAttr);
111         supportedAttributes.add(SVGNames::refYAttr);
112         supportedAttributes.add(SVGNames::markerWidthAttr);
113         supportedAttributes.add(SVGNames::markerHeightAttr);
114         supportedAttributes.add(SVGNames::orientAttr);
115     }
116     return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName);
117 }
118
119 void SVGMarkerElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
120 {
121     SVGParsingError parseError = NoError;
122
123     if (!isSupportedAttribute(name))
124         SVGElement::parseAttribute(name, value);
125     else if (name == SVGNames::markerUnitsAttr) {
126         SVGMarkerUnitsType propertyValue = SVGPropertyTraits<SVGMarkerUnitsType>::fromString(value);
127         if (propertyValue > 0)
128             setMarkerUnitsBaseValue(propertyValue);
129     } else if (name == SVGNames::refXAttr)
130         m_refX->setBaseValueAsString(value, AllowNegativeLengths, parseError);
131     else if (name == SVGNames::refYAttr)
132         m_refY->setBaseValueAsString(value, AllowNegativeLengths, parseError);
133     else if (name == SVGNames::markerWidthAttr)
134         m_markerWidth->setBaseValueAsString(value, ForbidNegativeLengths, parseError);
135     else if (name == SVGNames::markerHeightAttr)
136         m_markerHeight->setBaseValueAsString(value, ForbidNegativeLengths, parseError);
137     else if (name == SVGNames::orientAttr) {
138         SVGAngle angle;
139         SVGMarkerOrientType orientType = SVGPropertyTraits<SVGMarkerOrientType>::fromString(value, angle);
140         if (orientType > 0)
141             setOrientTypeBaseValue(orientType);
142         if (orientType == SVGMarkerOrientAngle)
143             setOrientAngleBaseValue(angle);
144     } else if (SVGFitToViewBox::parseAttribute(name, value, document(), parseError)) {
145     } else {
146         ASSERT_NOT_REACHED();
147     }
148
149     reportAttributeParsingError(parseError, name, value);
150 }
151
152 void SVGMarkerElement::svgAttributeChanged(const QualifiedName& attrName)
153 {
154     if (!isSupportedAttribute(attrName)) {
155         SVGElement::svgAttributeChanged(attrName);
156         return;
157     }
158
159     SVGElementInstance::InvalidationGuard invalidationGuard(this);
160
161     if (attrName == SVGNames::refXAttr
162         || attrName == SVGNames::refYAttr
163         || attrName == SVGNames::markerWidthAttr
164         || attrName == SVGNames::markerHeightAttr)
165         updateRelativeLengthsInformation();
166
167     RenderSVGResourceContainer* renderer = toRenderSVGResourceContainer(this->renderer());
168     if (renderer)
169         renderer->invalidateCacheAndMarkForLayout();
170 }
171
172 void SVGMarkerElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
173 {
174     SVGElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
175
176     if (changedByParser)
177         return;
178
179     if (RenderObject* object = renderer())
180         object->setNeedsLayout();
181 }
182
183 void SVGMarkerElement::setOrientToAuto()
184 {
185     setOrientTypeBaseValue(SVGMarkerOrientAuto);
186     setOrientAngleBaseValue(SVGAngle());
187
188     // Mark orientAttr dirty - the next XML DOM access of that attribute kicks in synchronization.
189     m_orientAngle.shouldSynchronize = true;
190     m_orientType.shouldSynchronize = true;
191     invalidateSVGAttributes();
192     svgAttributeChanged(orientAnglePropertyInfo()->attributeName);
193 }
194
195 void SVGMarkerElement::setOrientToAngle(const SVGAngle& angle)
196 {
197     setOrientTypeBaseValue(SVGMarkerOrientAngle);
198     setOrientAngleBaseValue(angle);
199
200     // Mark orientAttr dirty - the next XML DOM access of that attribute kicks in synchronization.
201     m_orientAngle.shouldSynchronize = true;
202     m_orientType.shouldSynchronize = true;
203     invalidateSVGAttributes();
204     svgAttributeChanged(orientAnglePropertyInfo()->attributeName);
205 }
206
207 RenderObject* SVGMarkerElement::createRenderer(RenderStyle*)
208 {
209     return new RenderSVGResourceMarker(this);
210 }
211
212 bool SVGMarkerElement::selfHasRelativeLengths() const
213 {
214     return m_refX->currentValue()->isRelative()
215         || m_refY->currentValue()->isRelative()
216         || m_markerWidth->currentValue()->isRelative()
217         || m_markerHeight->currentValue()->isRelative();
218 }
219
220 void SVGMarkerElement::synchronizeOrientType(SVGElement* contextElement)
221 {
222     ASSERT(contextElement);
223     SVGMarkerElement* ownerType = toSVGMarkerElement(contextElement);
224     if (!ownerType->m_orientType.shouldSynchronize)
225         return;
226
227     // If orient is not auto, the previous call to synchronizeOrientAngle already set the orientAttr to the right angle.
228     if (ownerType->m_orientType.value != SVGMarkerOrientAuto)
229         return;
230
231     DEFINE_STATIC_LOCAL(AtomicString, autoString, ("auto", AtomicString::ConstructFromLiteral));
232     ownerType->m_orientType.synchronize(ownerType, orientTypePropertyInfo()->attributeName, autoString);
233 }
234
235 PassRefPtr<SVGAnimatedProperty> SVGMarkerElement::lookupOrCreateOrientTypeWrapper(SVGElement* contextElement)
236 {
237     ASSERT(contextElement);
238     SVGMarkerElement* ownerType = toSVGMarkerElement(contextElement);
239     return SVGAnimatedProperty::lookupOrCreateWrapper<SVGMarkerElement, SVGAnimatedEnumerationPropertyTearOff<SVGMarkerOrientType>, SVGMarkerOrientType>
240            (ownerType, orientTypePropertyInfo(), ownerType->m_orientType.value);
241 }
242
243 PassRefPtr<SVGAnimatedEnumerationPropertyTearOff<SVGMarkerOrientType> > SVGMarkerElement::orientType()
244 {
245     m_orientType.shouldSynchronize = true;
246     return static_pointer_cast<SVGAnimatedEnumerationPropertyTearOff<SVGMarkerOrientType> >(lookupOrCreateOrientTypeWrapper(this));
247 }
248
249 }