1 /*
2 Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3 2004, 2005, 2006, 2008 Rob Buis <buis@kde.org>
4 Copyright (C) 2008 Apple Inc. All rights reserved.
5 Copyright (C) 2008 Alp Toker <alp@atoker.com>
6 Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au>
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
17
18 You should have received a copy of the GNU Library General Public License
19 along with this library; see the file COPYING.LIB. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA.
22 */
23
24 #include "config.h"
25
26 #if ENABLE(SVG)
27 #include "SVGElement.h"
28
29 #include "CSSCursorImageValue.h"
30 #include "DOMImplementation.h"
31 #include "Document.h"
32 #include "Event.h"
33 #include "EventListener.h"
34 #include "EventNames.h"
35 #include "FrameView.h"
36 #include "HTMLNames.h"
37 #include "MappedAttribute.h"
38 #include "RegisteredEventListener.h"
39 #include "RenderObject.h"
40 #include "SVGCursorElement.h"
41 #include "SVGElementInstance.h"
42 #include "SVGElementRareData.h"
43 #include "SVGNames.h"
44 #include "SVGResource.h"
45 #include "SVGSVGElement.h"
46 #include "SVGURIReference.h"
47 #include "SVGUseElement.h"
48 #include "ScriptEventListener.h"
49 #include "XMLNames.h"
50
51 namespace WebCore {
52
53 using namespace HTMLNames;
54
SVGElement(const QualifiedName & tagName,Document * document)55 SVGElement::SVGElement(const QualifiedName& tagName, Document* document)
56 : StyledElement(tagName, document, CreateElementZeroRefCount)
57 {
58 }
59
create(const QualifiedName & tagName,Document * document)60 PassRefPtr<SVGElement> SVGElement::create(const QualifiedName& tagName, Document* document)
61 {
62 return new SVGElement(tagName, document);
63 }
64
~SVGElement()65 SVGElement::~SVGElement()
66 {
67 if (!hasRareSVGData())
68 ASSERT(!SVGElementRareData::rareDataMap().contains(this));
69 else {
70 SVGElementRareData::SVGElementRareDataMap& rareDataMap = SVGElementRareData::rareDataMap();
71 SVGElementRareData::SVGElementRareDataMap::iterator it = rareDataMap.find(this);
72 ASSERT(it != rareDataMap.end());
73
74 SVGElementRareData* rareData = it->second;
75 if (SVGCursorElement* cursorElement = rareData->cursorElement())
76 cursorElement->removeClient(this);
77 if (CSSCursorImageValue* cursorImageValue = rareData->cursorImageValue())
78 cursorImageValue->removeReferencedElement(this);
79
80 delete rareData;
81 rareDataMap.remove(it);
82 }
83 }
84
rareSVGData() const85 SVGElementRareData* SVGElement::rareSVGData() const
86 {
87 ASSERT(hasRareSVGData());
88 return SVGElementRareData::rareDataFromMap(this);
89 }
90
ensureRareSVGData()91 SVGElementRareData* SVGElement::ensureRareSVGData()
92 {
93 if (hasRareSVGData())
94 return rareSVGData();
95
96 ASSERT(!SVGElementRareData::rareDataMap().contains(this));
97 SVGElementRareData* data = new SVGElementRareData;
98 SVGElementRareData::rareDataMap().set(this, data);
99 m_hasRareSVGData = true;
100 return data;
101 }
102
isSupported(StringImpl * feature,StringImpl * version) const103 bool SVGElement::isSupported(StringImpl* feature, StringImpl* version) const
104 {
105 return DOMImplementation::hasFeature(feature, version);
106 }
107
xmlbase() const108 String SVGElement::xmlbase() const
109 {
110 return getAttribute(XMLNames::baseAttr);
111 }
112
setXmlbase(const String & value,ExceptionCode &)113 void SVGElement::setXmlbase(const String& value, ExceptionCode&)
114 {
115 setAttribute(XMLNames::baseAttr, value);
116 }
117
ownerSVGElement() const118 SVGSVGElement* SVGElement::ownerSVGElement() const
119 {
120 Node* n = isShadowNode() ? const_cast<SVGElement*>(this)->shadowParentNode() : parentNode();
121 while (n) {
122 if (n->hasTagName(SVGNames::svgTag))
123 return static_cast<SVGSVGElement*>(n);
124
125 n = n->isShadowNode() ? n->shadowParentNode() : n->parentNode();
126 }
127
128 return 0;
129 }
130
viewportElement() const131 SVGElement* SVGElement::viewportElement() const
132 {
133 // This function needs shadow tree support - as RenderSVGContainer uses this function
134 // to determine the "overflow" property. <use> on <symbol> wouldn't work otherwhise.
135 Node* n = isShadowNode() ? const_cast<SVGElement*>(this)->shadowParentNode() : parentNode();
136 while (n) {
137 if (n->hasTagName(SVGNames::svgTag) || n->hasTagName(SVGNames::imageTag) || n->hasTagName(SVGNames::symbolTag))
138 return static_cast<SVGElement*>(n);
139
140 n = n->isShadowNode() ? n->shadowParentNode() : n->parentNode();
141 }
142
143 return 0;
144 }
145
accessDocumentSVGExtensions() const146 SVGDocumentExtensions* SVGElement::accessDocumentSVGExtensions() const
147 {
148 // This function is provided for use by SVGAnimatedProperty to avoid
149 // global inclusion of Document.h in SVG code.
150 return document() ? document()->accessSVGExtensions() : 0;
151 }
152
mapInstanceToElement(SVGElementInstance * instance)153 void SVGElement::mapInstanceToElement(SVGElementInstance* instance)
154 {
155 ASSERT(instance);
156
157 HashSet<SVGElementInstance*>& instances = ensureRareSVGData()->elementInstances();
158 ASSERT(!instances.contains(instance));
159
160 instances.add(instance);
161 }
162
removeInstanceMapping(SVGElementInstance * instance)163 void SVGElement::removeInstanceMapping(SVGElementInstance* instance)
164 {
165 ASSERT(instance);
166 ASSERT(hasRareSVGData());
167
168 HashSet<SVGElementInstance*>& instances = rareSVGData()->elementInstances();
169 ASSERT(instances.contains(instance));
170
171 instances.remove(instance);
172 }
173
instancesForElement() const174 const HashSet<SVGElementInstance*>& SVGElement::instancesForElement() const
175 {
176 if (!hasRareSVGData()) {
177 DEFINE_STATIC_LOCAL(HashSet<SVGElementInstance*>, emptyInstances, ());
178 return emptyInstances;
179 }
180 return rareSVGData()->elementInstances();
181 }
182
setCursorElement(SVGCursorElement * cursorElement)183 void SVGElement::setCursorElement(SVGCursorElement* cursorElement)
184 {
185 ensureRareSVGData()->setCursorElement(cursorElement);
186 }
187
setCursorImageValue(CSSCursorImageValue * cursorImageValue)188 void SVGElement::setCursorImageValue(CSSCursorImageValue* cursorImageValue)
189 {
190 ensureRareSVGData()->setCursorImageValue(cursorImageValue);
191 }
192
parseMappedAttribute(MappedAttribute * attr)193 void SVGElement::parseMappedAttribute(MappedAttribute* attr)
194 {
195 // standard events
196 if (attr->name() == onloadAttr)
197 setAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(this, attr));
198 else if (attr->name() == onclickAttr)
199 setAttributeEventListener(eventNames().clickEvent, createAttributeEventListener(this, attr));
200 else if (attr->name() == onmousedownAttr)
201 setAttributeEventListener(eventNames().mousedownEvent, createAttributeEventListener(this, attr));
202 else if (attr->name() == onmousemoveAttr)
203 setAttributeEventListener(eventNames().mousemoveEvent, createAttributeEventListener(this, attr));
204 else if (attr->name() == onmouseoutAttr)
205 setAttributeEventListener(eventNames().mouseoutEvent, createAttributeEventListener(this, attr));
206 else if (attr->name() == onmouseoverAttr)
207 setAttributeEventListener(eventNames().mouseoverEvent, createAttributeEventListener(this, attr));
208 else if (attr->name() == onmouseupAttr)
209 setAttributeEventListener(eventNames().mouseupEvent, createAttributeEventListener(this, attr));
210 else if (attr->name() == SVGNames::onfocusinAttr)
211 setAttributeEventListener(eventNames().DOMFocusInEvent, createAttributeEventListener(this, attr));
212 else if (attr->name() == SVGNames::onfocusoutAttr)
213 setAttributeEventListener(eventNames().DOMFocusOutEvent, createAttributeEventListener(this, attr));
214 else if (attr->name() == SVGNames::onactivateAttr)
215 setAttributeEventListener(eventNames().DOMActivateEvent, createAttributeEventListener(this, attr));
216 else
217 StyledElement::parseMappedAttribute(attr);
218 }
219
haveLoadedRequiredResources()220 bool SVGElement::haveLoadedRequiredResources()
221 {
222 Node* child = firstChild();
223 while (child) {
224 if (child->isSVGElement() && !static_cast<SVGElement*>(child)->haveLoadedRequiredResources())
225 return false;
226 child = child->nextSibling();
227 }
228 return true;
229 }
230
hasLoadListener(Node * node)231 static bool hasLoadListener(Node* node)
232 {
233 if (node->hasEventListeners(eventNames().loadEvent))
234 return true;
235
236 for (node = node->parentNode(); node && node->isElementNode(); node = node->parentNode()) {
237 const EventListenerVector& entry = node->getEventListeners(eventNames().loadEvent);
238 for (size_t i = 0; i < entry.size(); ++i) {
239 if (entry[i].useCapture)
240 return true;
241 }
242 }
243
244 return false;
245 }
246
sendSVGLoadEventIfPossible(bool sendParentLoadEvents)247 void SVGElement::sendSVGLoadEventIfPossible(bool sendParentLoadEvents)
248 {
249 RefPtr<SVGElement> currentTarget = this;
250 while (currentTarget && currentTarget->haveLoadedRequiredResources()) {
251 RefPtr<Node> parent;
252 if (sendParentLoadEvents)
253 parent = currentTarget->parentNode(); // save the next parent to dispatch too incase dispatching the event changes the tree
254 if (hasLoadListener(currentTarget.get())) {
255 RefPtr<Event> event = Event::create(eventNames().loadEvent, false, false);
256 event->setTarget(currentTarget);
257 currentTarget->dispatchGenericEvent(event.release());
258 }
259 currentTarget = (parent && parent->isSVGElement()) ? static_pointer_cast<SVGElement>(parent) : 0;
260 }
261 }
262
finishParsingChildren()263 void SVGElement::finishParsingChildren()
264 {
265 StyledElement::finishParsingChildren();
266
267 // finishParsingChildren() is called when the close tag is reached for an element (e.g. </svg>)
268 // we send SVGLoad events here if we can, otherwise they'll be sent when any required loads finish
269 sendSVGLoadEventIfPossible();
270 }
271
childShouldCreateRenderer(Node * child) const272 bool SVGElement::childShouldCreateRenderer(Node* child) const
273 {
274 if (child->isSVGElement())
275 return static_cast<SVGElement*>(child)->isValid();
276 return false;
277 }
278
insertedIntoDocument()279 void SVGElement::insertedIntoDocument()
280 {
281 StyledElement::insertedIntoDocument();
282 SVGDocumentExtensions* extensions = document()->accessSVGExtensions();
283
284 String resourceId = SVGURIReference::getTarget(getAttribute(idAttributeName()));
285 if (extensions->isPendingResource(resourceId)) {
286 std::auto_ptr<HashSet<SVGStyledElement*> > clients(extensions->removePendingResource(resourceId));
287 if (clients->isEmpty())
288 return;
289
290 HashSet<SVGStyledElement*>::const_iterator it = clients->begin();
291 const HashSet<SVGStyledElement*>::const_iterator end = clients->end();
292
293 for (; it != end; ++it)
294 (*it)->buildPendingResource();
295
296 SVGResource::invalidateClients(*clients);
297 }
298 }
299
attributeChanged(Attribute * attr,bool preserveDecls)300 void SVGElement::attributeChanged(Attribute* attr, bool preserveDecls)
301 {
302 ASSERT(attr);
303 if (!attr)
304 return;
305
306 StyledElement::attributeChanged(attr, preserveDecls);
307 svgAttributeChanged(attr->name());
308 }
309
updateAnimatedSVGAttribute(const QualifiedName & name) const310 void SVGElement::updateAnimatedSVGAttribute(const QualifiedName& name) const
311 {
312 ASSERT(!m_areSVGAttributesValid);
313
314 if (m_synchronizingSVGAttributes)
315 return;
316
317 m_synchronizingSVGAttributes = true;
318
319 const_cast<SVGElement*>(this)->synchronizeProperty(name);
320 if (name == anyQName())
321 m_areSVGAttributesValid = true;
322
323 m_synchronizingSVGAttributes = false;
324 }
325
eventParentNode()326 ContainerNode* SVGElement::eventParentNode()
327 {
328 if (Node* shadowParent = shadowParentNode()) {
329 ASSERT(shadowParent->isContainerNode());
330 return static_cast<ContainerNode*>(shadowParent);
331 }
332 return StyledElement::eventParentNode();
333 }
334
335 }
336
337 #endif // ENABLE(SVG)
338