1 /*
2 Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19 */
20
21 #include "config.h"
22
23 #if ENABLE(SVG)
24 #include "SVGMarkerElement.h"
25
26 #include "MappedAttribute.h"
27 #include "PlatformString.h"
28 #include "RenderSVGViewportContainer.h"
29 #include "SVGAngle.h"
30 #include "SVGFitToViewBox.h"
31 #include "SVGLength.h"
32 #include "SVGNames.h"
33 #include "SVGPreserveAspectRatio.h"
34 #include "SVGSVGElement.h"
35
36 namespace WebCore {
37
38 char SVGOrientTypeAttrIdentifier[] = "SVGOrientTypeAttr";
39 char SVGOrientAngleAttrIdentifier[] = "SVGOrientAngleAttr";
40
SVGMarkerElement(const QualifiedName & tagName,Document * doc)41 SVGMarkerElement::SVGMarkerElement(const QualifiedName& tagName, Document* doc)
42 : SVGStyledElement(tagName, doc)
43 , SVGLangSpace()
44 , SVGExternalResourcesRequired()
45 , SVGFitToViewBox()
46 , m_refX(this, SVGNames::refXAttr, LengthModeWidth)
47 , m_refY(this, SVGNames::refYAttr, LengthModeHeight)
48 , m_markerWidth(this, SVGNames::markerWidthAttr, LengthModeWidth, "3")
49 , m_markerHeight(this, SVGNames::markerHeightAttr, LengthModeHeight, "3")
50 , m_markerUnits(this, SVGNames::markerUnitsAttr, SVG_MARKERUNITS_STROKEWIDTH)
51 , m_orientType(this, SVGNames::orientAttr, SVG_MARKER_ORIENT_ANGLE)
52 , m_orientAngle(this, SVGNames::orientAttr, SVGAngle::create())
53 {
54 // Spec: If the markerWidth/markerHeight attribute is not specified, the effect is as if a value of "3" were specified.
55 }
56
~SVGMarkerElement()57 SVGMarkerElement::~SVGMarkerElement()
58 {
59 // Call detach() here because if we wait until ~Node() calls it, we crash during
60 // RenderSVGViewportContainer destruction, as the renderer assumes that the element
61 // is still fully constructed. See <https://bugs.webkit.org/show_bug.cgi?id=21293>.
62 if (renderer())
63 detach();
64 }
65
parseMappedAttribute(MappedAttribute * attr)66 void SVGMarkerElement::parseMappedAttribute(MappedAttribute* attr)
67 {
68 if (attr->name() == SVGNames::markerUnitsAttr) {
69 if (attr->value() == "userSpaceOnUse")
70 setMarkerUnitsBaseValue(SVG_MARKERUNITS_USERSPACEONUSE);
71 else if (attr->value() == "strokeWidth")
72 setMarkerUnitsBaseValue(SVG_MARKERUNITS_STROKEWIDTH);
73 } else if (attr->name() == SVGNames::refXAttr)
74 setRefXBaseValue(SVGLength(LengthModeWidth, attr->value()));
75 else if (attr->name() == SVGNames::refYAttr)
76 setRefYBaseValue(SVGLength(LengthModeHeight, attr->value()));
77 else if (attr->name() == SVGNames::markerWidthAttr)
78 setMarkerWidthBaseValue(SVGLength(LengthModeWidth, attr->value()));
79 else if (attr->name() == SVGNames::markerHeightAttr)
80 setMarkerHeightBaseValue(SVGLength(LengthModeHeight, attr->value()));
81 else if (attr->name() == SVGNames::orientAttr) {
82 RefPtr<SVGAngle> angle = SVGAngle::create();
83
84 if (attr->value() == "auto")
85 setOrientTypeBaseValue(SVG_MARKER_ORIENT_AUTO);
86 else {
87 angle->setValueAsString(attr->value());
88 setOrientTypeBaseValue(SVG_MARKER_ORIENT_ANGLE);
89 }
90
91 setOrientAngleBaseValue(angle.get());
92 } else {
93 if (SVGLangSpace::parseMappedAttribute(attr))
94 return;
95 if (SVGExternalResourcesRequired::parseMappedAttribute(attr))
96 return;
97 if (SVGFitToViewBox::parseMappedAttribute(attr))
98 return;
99
100 SVGStyledElement::parseMappedAttribute(attr);
101 }
102 }
103
svgAttributeChanged(const QualifiedName & attrName)104 void SVGMarkerElement::svgAttributeChanged(const QualifiedName& attrName)
105 {
106 SVGStyledElement::svgAttributeChanged(attrName);
107
108 if (!m_marker)
109 return;
110
111 if (attrName == SVGNames::markerUnitsAttr || attrName == SVGNames::refXAttr ||
112 attrName == SVGNames::refYAttr || attrName == SVGNames::markerWidthAttr ||
113 attrName == SVGNames::markerHeightAttr || attrName == SVGNames::orientAttr ||
114 SVGLangSpace::isKnownAttribute(attrName) ||
115 SVGExternalResourcesRequired::isKnownAttribute(attrName) ||
116 SVGFitToViewBox::isKnownAttribute(attrName) ||
117 SVGStyledElement::isKnownAttribute(attrName)) {
118 if (renderer())
119 renderer()->setNeedsLayout(true);
120
121 m_marker->invalidate();
122 }
123 }
124
childrenChanged(bool changedByParser,Node * beforeChange,Node * afterChange,int childCountDelta)125 void SVGMarkerElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
126 {
127 SVGStyledElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
128
129 if (!m_marker)
130 return;
131
132 if (renderer())
133 renderer()->setNeedsLayout(true);
134
135 m_marker->invalidate();
136 }
137
setOrientToAuto()138 void SVGMarkerElement::setOrientToAuto()
139 {
140 setOrientTypeBaseValue(SVG_MARKER_ORIENT_AUTO);
141
142 RefPtr<SVGAngle> angle = SVGAngle::create();
143 setOrientAngleBaseValue(angle.get());
144
145 if (!m_marker)
146 return;
147
148 if (renderer())
149 renderer()->setNeedsLayout(true);
150
151 m_marker->invalidate();
152 }
153
setOrientToAngle(PassRefPtr<SVGAngle> angle)154 void SVGMarkerElement::setOrientToAngle(PassRefPtr<SVGAngle> angle)
155 {
156 setOrientTypeBaseValue(SVG_MARKER_ORIENT_ANGLE);
157 setOrientAngleBaseValue(angle.get());
158
159 if (!m_marker)
160 return;
161
162 if (renderer())
163 renderer()->setNeedsLayout(true);
164
165 m_marker->invalidate();
166 }
167
canvasResource()168 SVGResource* SVGMarkerElement::canvasResource()
169 {
170 if (!m_marker)
171 m_marker = SVGResourceMarker::create();
172
173 m_marker->setMarker(toRenderSVGViewportContainer(renderer()));
174
175 if (orientType() == SVG_MARKER_ORIENT_ANGLE) {
176 if (orientAngle())
177 m_marker->setAngle(orientAngle()->value());
178 } else
179 m_marker->setAutoAngle();
180
181 m_marker->setRef(refX().value(this), refY().value(this));
182 m_marker->setUseStrokeWidth(markerUnits() == SVG_MARKERUNITS_STROKEWIDTH);
183
184 return m_marker.get();
185 }
186
createRenderer(RenderArena * arena,RenderStyle *)187 RenderObject* SVGMarkerElement::createRenderer(RenderArena* arena, RenderStyle*)
188 {
189 RenderSVGViewportContainer* markerContainer = new (arena) RenderSVGViewportContainer(this);
190 markerContainer->setDrawsContents(false); // Marker contents will be explicitly drawn.
191 return markerContainer;
192 }
193
194 }
195
196 #endif // ENABLE(SVG)
197