• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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